Skip to content

Commit

Permalink
Merge pull request #1865 from emanlove/add-expected-conditions-1827
Browse files Browse the repository at this point in the history
Add expected conditions 1827
  • Loading branch information
emanlove committed Apr 14, 2024
2 parents f4f5d5d + cc41bc1 commit cafc0b4
Show file tree
Hide file tree
Showing 17 changed files with 335 additions and 32 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
matrix:
python-version: [3.8, 3.11] # 3.12, pypy-3.9
rf-version: [5.0.1, 6.1.1, 7.0]
selenium-version: [4.14.0, 4.15.2, 4.16.0] #4.17.0, 4.18.0
selenium-version: [4.14.0, 4.15.2, 4.16.0, 4.17.2, 4.18.1, 4.19.0]
browser: [firefox, chrome, headlesschrome] #edge

steps:
Expand Down Expand Up @@ -88,7 +88,7 @@ jobs:
# xvfb-run --auto-servernum python atest/run.py --zip headlesschrome --grid True

- uses: actions/upload-artifact@v1
if: success() || failure()
if: failure()
with:
name: SeleniumLibrary Test results
path: atest/zip_results
34 changes: 34 additions & 0 deletions atest/acceptance/expected_conditions.robot.PROTOTYPE
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
*** Test Cases ***
# Wait Until Element State Is (Not)
# Get Element State
# Element States Should (Not) Be

Check waiting for condition that takes a element
Fail

Check waiting for condition that takes a title
Fail

Check waiting for condition that takes a url
Fail
Wait Until url contains google
# verify took 2 seconds

Check waiting for condition that takes locator and string
Wait Until Element State Is ${condition} ${locator} ${string}
Wait Until Element State Is ${condition} ${element}
Wait Until Condition Is ${condition} ${target}
Wait Until Condition Is ${condition} ${whatelse you need for this condition}


Wait Until State Is number_of_windows_to_be
Wait Until Expected Condition Is number_of_windows_to_be
Wait Until Condition Is number of windows to be 5
Wait Until Condition Is text to be present in element attribute //some/xpath/to/an/element href http://hello

Wait Until Condition Is number of windows to be 5 text to be present in element attribute //some/xpath/to/an/element href http://hello

Wait Until number of windows to be 5
Wait Until text to be present in element attribute //some/xpath/to/an/element href http://hello
Get Condition
Is number of windows to be 5
10 changes: 5 additions & 5 deletions atest/acceptance/keywords/choose_file.robot
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@ Choose File With Grid From Library Using SL choose_file method

Input Text Should Work Same Way When Not Using Grid
[Documentation]
... LOG 1:6 DEBUG GLOB: POST*/session/*/clear {*
... LOG 1:9 DEBUG Finished Request
... LOG 1:10 DEBUG GLOB: POST*/session/*/value*"text": "*
... LOG 1:13 DEBUG Finished Request
... LOG 1:14 DEBUG NONE
... LOG 1:6 DEBUG GLOB: POST*/session/*/clear {*
... LOG 1:9 DEBUG Finished Request
... LOG 1:10 DEBUG REGEXP: POST.*/session/.*/value.*['\\\"]text['\\\"]: ['\\\"].*
... LOG 1:13 DEBUG Finished Request
... LOG 1:14 DEBUG NONE
[Tags] NoGrid
[Setup] Touch ${CURDIR}${/}temp.txt
Input Text file_to_upload ${CURDIR}${/}temp.txt
Expand Down
2 changes: 1 addition & 1 deletion atest/acceptance/keywords/click_element.robot
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Click Element Action Chain
[Tags] NoGrid
[Documentation]
... LOB 1:1 INFO Clicking 'singleClickButton' using an action chain.
... LOG 1:6 DEBUG GLOB: *actions {"actions": [{*
... LOG 1:6 DEBUG REGEXP: .*actions {['\\\"]actions['\\\"]: \\\[\\\{.*
Click Element singleClickButton action_chain=True
Element Text Should Be output single clicked

Expand Down
52 changes: 52 additions & 0 deletions atest/acceptance/keywords/expected_conditions.robot
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
*** Settings ***
Test Setup Go To Page "javascript/expected_conditions.html"
Resource ../resource.robot
*** Test Cases ***
Wait For Expected Conditions One Argument
Title Should Be Original
Click Element link=delayed change title
Wait For Expected Condition title_is Delayed
Title Should Be Delayed
Wait For Expected Condition Times out within set timeout
[Documentation] FAIL REGEXP: TimeoutException: Message: Expected Condition not met within set timeout of 0.3*
Title Should Be Original
Click Element link=delayed change title
Wait For Expected Condition title_is Delayed timeout=0.3
Wait For Expected Conditions using WebElement as locator
Click Button Change the button state
${dynamic_btn}= Get WebElement id:enabledDisabledBtn
Wait For Expected Condition element_to_be_clickable ${dynamic_btn}
Wait For Expected Conditions Where Condition Written With Spaces
Title Should Be Original
Click Element link=delayed change title
Wait For Expected Condition title is Delayed
Title Should Be Delayed
Wait For Expected Conditions Where Condition Is Variable
${condition}= Set Variable title is
Title Should Be Original
Click Element link=delayed change title
Wait For Expected Condition ${condition} Delayed
Title Should Be Delayed
Wait For Expected Conditions Where Condition Is Strange Case
Click Button Change the button state
${dynamic_btn}= Get WebElement id:enabledDisabledBtn
Wait For Expected Condition EleMENT tO BE cLiCkAbLe ${dynamic_btn}
Wait For Non Existing Expected Conditions
Click Button Change the button state
${dynamic_btn}= Get WebElement id:enabledDisabledBtn
Run Keyword And Expect Error this_is_not_an_expected_con_dition is an unknown expected condition
... Wait For Expected Condition this_is not an expected con dition ${dynamic_btn}
Wait For Expected Conditions When Condition Includes Locator
Title Should Be Original
${byElem}= Evaluate ("id","added_btn")
Click Element link:delayed add element
Wait For Expected Condition Presence Of Element Located ${byElem}
Click Element id:added_btn
6 changes: 3 additions & 3 deletions atest/acceptance/keywords/page_load_timeout.robot
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Test Teardown Close Browser And Reset Page Load Timeout
*** Test Cases ***
Should Open Browser With Default Page Load Timeout
[Documentation] Verify that 'Open Browser' changes the page load timeout.
... LOG 1.1.1:27 DEBUG REGEXP: POST http://localhost:\\d{2,5}/session/[a-f0-9-]+/timeouts {"pageLoad": 300000}
... LOG 1.1.1:27 DEBUG REGEXP: POST http://localhost:\\d{2,5}/session/[a-f0-9-]+/timeouts {['\\\"]pageLoad['\\\"]: 300000}
... LOG 1.1.1:29 DEBUG STARTS: Remote response: status=200
# Note: previous log check was 33 and 37. Recording to see if something is swtiching back and forth
Open Browser To Start Page
Expand All @@ -21,8 +21,8 @@ Should Run Into Timeout Exception

Should Set Page Load Timeout For All Opened Browsers
[Documentation] One browser is already opened as global suite setup.
... LOG 2:1 DEBUG REGEXP: POST http://localhost:\\d{2,5}/session/[a-f0-9-]+/timeouts {"pageLoad": 5000}
... LOG 2:5 DEBUG REGEXP: POST http://localhost:\\d{2,5}/session/[a-f0-9-]+/timeouts {"pageLoad": 5000}
... LOG 2:1 DEBUG REGEXP: POST http://localhost:\\d{2,5}/session/[a-f0-9-]+/timeouts {['\\\"]pageLoad['\\\"]: 5000}
... LOG 2:5 DEBUG REGEXP: POST http://localhost:\\d{2,5}/session/[a-f0-9-]+/timeouts {['\\\"]pageLoad['\\\"]: 5000}
Open Browser To Start Page
Set Selenium Page Load Timeout 5 s

Expand Down
24 changes: 12 additions & 12 deletions atest/acceptance/multiple_browsers_options.robot
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,32 @@ Documentation Creating test which would work on all browser is not possible.
*** Test Cases ***
Chrome Browser With Selenium Options As String
[Documentation]
... LOG 1:14 DEBUG GLOB: *"goog:chromeOptions"*
... LOG 1:14 DEBUG GLOB: *args": ["--disable-dev-shm-usage"?*
... LOG 1:14 DEBUG REGEXP: .*['\\\"]goog:chromeOptions['\\\"].*
... LOG 1:14 DEBUG REGEXP: .*args['\\\"]: \\\[['\\\"]--disable-dev-shm-usage['\\\"].*
Open Browser ${FRONT PAGE} ${BROWSER} remote_url=${REMOTE_URL}
... desired_capabilities=${DESIRED_CAPABILITIES} options=add_argument("--disable-dev-shm-usage")

Chrome Browser With Selenium Options As String With Attribute As True
[Documentation]
... LOG 1:14 DEBUG GLOB: *"goog:chromeOptions"*
... LOG 1:14 DEBUG GLOB: *args": ["--disable-dev-shm-usage"?*
... LOG 1:14 DEBUG GLOB: *"--headless=new"*
... LOG 1:14 DEBUG REGEXP: .*['\\\"]goog:chromeOptions['\\\"].*
... LOG 1:14 DEBUG REGEXP: .*args['\\\"]: \\\[['\\\"]--disable-dev-shm-usage['\\\"].*
... LOG 1:14 DEBUG REGEXP: .*['\\\"]--headless=new['\\\"].*
Open Browser ${FRONT PAGE} ${BROWSER} remote_url=${REMOTE_URL}
... desired_capabilities=${DESIRED_CAPABILITIES} options=add_argument ( "--disable-dev-shm-usage" ) ; add_argument ( "--headless=new" )

Chrome Browser With Selenium Options With Complex Object
[Tags] NoGrid
[Documentation]
... LOG 1:14 DEBUG GLOB: *"goog:chromeOptions"*
... LOG 1:14 DEBUG GLOB: *"mobileEmulation": {"deviceName": "Galaxy S5"*
... LOG 1:14 DEBUG GLOB: *args": ["--disable-dev-shm-usage"?*
... LOG 1:14 DEBUG REGEXP: .*['\\\"]goog:chromeOptions['\\\"].*
... LOG 1:14 DEBUG REGEXP: .*['\\\"]mobileEmulation['\\\"]: {['\\\"]deviceName['\\\"]: ['\\\"]Galaxy S5['\\\"].*
... LOG 1:14 DEBUG REGEXP: .*args['\\\"]: \\\[['\\\"]--disable-dev-shm-usage['\\\"].*
Open Browser ${FRONT PAGE} ${BROWSER} remote_url=${REMOTE_URL}
... desired_capabilities=${DESIRED_CAPABILITIES} options=add_argument ( "--disable-dev-shm-usage" ) ; add_experimental_option( "mobileEmulation" , { 'deviceName' : 'Galaxy S5'})

Chrome Browser With Selenium Options Object
[Documentation]
... LOG 2:14 DEBUG GLOB: *"goog:chromeOptions"*
... LOG 2:14 DEBUG GLOB: *args": ["--disable-dev-shm-usage"?*
... LOG 2:14 DEBUG REGEXP: .*['\\\"]goog:chromeOptions['\\\"].*
... LOG 2:14 DEBUG REGEXP: .*args['\\\"]: \\\[['\\\"]--disable-dev-shm-usage['\\\"].*
${options} = Get Chrome Options
Open Browser ${FRONT PAGE} ${BROWSER} remote_url=${REMOTE_URL}
... desired_capabilities=${DESIRED_CAPABILITIES} options=${options}
Expand All @@ -47,8 +47,8 @@ Chrome Browser With Selenium Options Invalid Method

Chrome Browser With Selenium Options Argument With Semicolon
[Documentation]
... LOG 1:14 DEBUG GLOB: *"goog:chromeOptions"*
... LOG 1:14 DEBUG GLOB: *["has;semicolon"*
... LOG 1:14 DEBUG REGEXP: .*['\\\"]goog:chromeOptions['\\\"].*
... LOG 1:14 DEBUG REGEXP: .*\\\[['\\\"]has;semicolon['\\\"].*
Open Browser ${FRONT PAGE} ${BROWSER} remote_url=${REMOTE_URL}
... desired_capabilities=${DESIRED_CAPABILITIES} options=add_argument("has;semicolon")

Expand Down
7 changes: 7 additions & 0 deletions atest/resources/html/javascript/dynamic_content.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,17 @@
container = document.getElementById(target_container);
container.appendChild(p);
}

function delayed_title_change() {
setTimeout(function(){
document.title='Delayed';
},600);
}
</script>
</head>
<body>
<a href="javascript:return false;" onclick="document.title='Changed'; return false;">change title</a><br/>
<a href="javascript:return false;" onclick="delayed_title_change(); return false;">delayed change title</a><br/>
<a href="javascript:return false;" onclick="add_content('target', 'added content'); return false;">add content</a><br/>
<a id="unicode" href="javascript:return false;" onclick="document.title='äää'; return false;">title to ääää</a><br/>
<p>
Expand Down
95 changes: 95 additions & 0 deletions atest/resources/html/javascript/expected_conditions.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>Original</title>
<!-- Note the timeouts in the functions are chosen such they constitute
a set with distinct subset sums. That is is a combination of any two
or more were to be executed the total time for that distinct combination
would be unique. This was done so we could do a ALL/AND/OR type of test
and know that with the combination of expected conditions the execution
was successful as the unique time took place. -->
<!-- The set we are using is {6,9,11,12,13} -->
<!-- (could also use {3,5,6,7} which would reduce total time)-->
<script type="text/javascript">
function add_content(target_container, content) {
p = document.createElement('p');
p.appendChild(document.createTextNode(content));
container = document.getElementById(target_container);
container.appendChild(p);
}

function delayed_button_state() {
setTimeout(function() {
state_btn = document.getElementById('enabledDisabledBtn')
if (state_btn.hasAttribute("disabled")) {
state_btn.removeAttribute("disabled")
state_btn.value = "Enabled"
} else {
state_btn.setAttribute("disabled", "")
state_btn.value = "Disabled"
}
},900)
}
function delayed_title_change() {
setTimeout(function(){
document.title='Delayed';
},600);
}

function delayed_add_element() {
setTimeout(function(){
const newElem = document.createElement("input");
newElem.setAttribute("type", "button");
newElem.setAttribute("id", "added_btn");
newElem.setAttribute("value", "Added Button");
const container = document.getElementById("container");
document.body.insertBefore(newElem, container);
},1100);
}
</script>
</head>
<body>
<a href="javascript:return false;" onclick="document.title='Changed'; return false;">change title</a><br/>
<a href="javascript:return false;" onclick="delayed_title_change(); return false;">delayed change title</a><br/>
<a href="javascript:return false;" onclick="delayed_add_element(); return fales;">delayed add element</a><br/>
<a href="javascript:return false;" onclick="add_content('target', 'added content'); return false;">add content</a><br/>
<a id="unicode" href="javascript:return false;" onclick="document.title='äää'; return false;">title to ääää</a><br/>
<p>
<input type="radio" name="group" value="title"
onclick="document.title='Changed by Button';" />Change Title<br/>
<input type="radio" name="group" value="content"
onclick="add_content('button_target', 'added by button');"/>Add Content<br/>
</p>
<div id="target">
</div>
<div id="button_target">
</div>
<form name=myform>
<input type=button value="Change the title"
onClick="if(confirm('Really change the title?'))
document.title += ' Changed!';" >
</form>
<p>
<input type=button id=stateChangeBtn value="Change the button state"
onClick="delayed_button_state()" />
<input type=button id=enabledDisabledBtn value="Disabled"
disabled />
</p>
<p>
<div id="container"></div>
</p>
<p>
<form name=titleChanger>
<td>
<input type=text id=titleChangeTxt value="Enter Title here">
</td>
<td>
<input type=button id=titleChangeBtn value="Set Title"
onClick="document.title = document.getElementById('titleChangeTxt').value;" >
</td>
</form>
</p>
</body>
</html>

9 changes: 5 additions & 4 deletions atest/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@

from robot import rebot_cli
from robot import __version__ as robot_version
from selenium import __version__ as selenium_version
from robot.utils import is_truthy

try:
Expand Down Expand Up @@ -251,15 +252,15 @@ def process_output(browser):
return exit.code


def create_zip():
def create_zip(browser = None):
if os.path.exists(ZIP_DIR):
shutil.rmtree(ZIP_DIR)
os.mkdir(ZIP_DIR)
python_version = platform.python_version()
zip_name = f"rf-{robot_version}-python-{python_version}.zip"
zip_name = f"rf-{robot_version}-python-{python_version}-selenium-{selenium_version}-{browser}.zip"
zip_path = os.path.join(ZIP_DIR, zip_name)
print("Zip created in: %s" % zip_path)
zip_file = zipfile.ZipFile(zip_path, "w")
zip_file = zipfile.ZipFile(zip_path, "a")
for root, dirs, files in os.walk(RESULTS_DIR):
for file in files:
file_path = os.path.join(root, file)
Expand Down Expand Up @@ -326,5 +327,5 @@ def create_zip():
interpreter, browser, rf_options, selenium_grid, event_firing_webdriver
)
if args.zip:
create_zip()
create_zip(browser)
sys.exit(failures)
2 changes: 2 additions & 0 deletions src/SeleniumLibrary/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
BrowserManagementKeywords,
CookieKeywords,
ElementKeywords,
ExpectedConditionKeywords,
FormElementKeywords,
FrameKeywords,
JavaScriptKeywords,
Expand Down Expand Up @@ -490,6 +491,7 @@ def __init__(
BrowserManagementKeywords(self),
CookieKeywords(self),
ElementKeywords(self),
ExpectedConditionKeywords(self),
FormElementKeywords(self),
FrameKeywords(self),
JavaScriptKeywords(self),
Expand Down
4 changes: 4 additions & 0 deletions src/SeleniumLibrary/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,7 @@ class NoOpenBrowser(SeleniumLibraryException):

class PluginError(SeleniumLibraryException):
pass


class UnkownExpectedCondition(SeleniumLibraryException):
pass
1 change: 1 addition & 0 deletions src/SeleniumLibrary/keywords/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from .browsermanagement import BrowserManagementKeywords # noqa
from .cookie import CookieKeywords # noqa
from .element import ElementKeywords # noqa
from .expectedconditions import ExpectedConditionKeywords # noqa
from .formelement import FormElementKeywords # noqa
from .frames import FrameKeywords # noqa
from .javascript import JavaScriptKeywords # noqa
Expand Down

0 comments on commit cafc0b4

Please sign in to comment.