Open pmartinez1 opened 2 months ago
Visit the deploys page to approve it
Name | Link |
---|---|
Latest commit | 64fae4b34addeea5bc995cc6dec449b02d1ca8d6 |
⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪ |
🧪 PR contains tests |
🔒 No security concerns identified |
⚡ Key issues to review Resource Management The WebDriver instances are not properly closed using a context manager or try-finally block, which may lead to resource leaks. Test Isolation The tests are not properly isolated, as they share the same WebDriver instance across multiple test functions. |
Category | Suggestion | Score |
Best practice |
Use a context manager for WebDriver to ensure proper resource cleanup___ **Consider using a context manager (with statement) for the WebDriver to ensure propercleanup of resources, even if an exception occurs.** [examples/python/tests/elements/test_locators.py [7-11]](https://github.com/SeleniumHQ/seleniumhq.github.io/pull/1903/files#diff-37a84073184f55bf24b44b3a435c07704ca453e3d74fac87370df04efec76cb8R7-R11) ```diff -driver = webdriver.Chrome() -driver.get("https://www.selenium.dev/") +with webdriver.Chrome() as driver: + driver.get("https://www.selenium.dev/") + driver.find_element(By.CLASS_NAME, "td-home") -driver.find_element(By.CLASS_NAME, "td-home") - -driver.quit() - ``` - [ ] **Apply this suggestion** Suggestion importance[1-10]: 9Why: Using a context manager for WebDriver is a best practice that ensures resources are properly cleaned up even if an exception occurs, improving code reliability and maintainability. | 9 |
Improve code block formatting for consistency and readability___ **Use consistent formatting for the Python code blocks across all examples. Add ablank line after the opening triple backticks and before the closing triple backticks to improve readability.** [website_and_docs/content/documentation/webdriver/elements/locators.en.md [84-85]](https://github.com/SeleniumHQ/seleniumhq.github.io/pull/1903/files#diff-bad5c08d78f84e8bd7528d1a2a3181973375147d3f8bc5b9678cfce7dbe76aabR84-R85) ```diff {{< tab header="Python" text=true >}} + {{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L10" >}} ``` - [ ] **Apply this suggestion** Suggestion importance[1-10]: 7Why: The suggestion improves readability by adding a blank line in the code block, which is a minor but beneficial enhancement for consistency across examples. | 7 | |
Enhancement |
Add an explicit wait before finding elements to improve test reliability___ **Consider adding an explicit wait before finding elements to ensure the page hasloaded completely, improving test reliability.** [examples/python/tests/elements/test_locators.py [7-11]](https://github.com/SeleniumHQ/seleniumhq.github.io/pull/1903/files#diff-37a84073184f55bf24b44b3a435c07704ca453e3d74fac87370df04efec76cb8R7-R11) ```diff +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC + driver = webdriver.Chrome() driver.get("https://www.selenium.dev/") -driver.find_element(By.CLASS_NAME, "td-home") +element = WebDriverWait(driver, 10).until( + EC.presence_of_element_located((By.CLASS_NAME, "td-home")) +) driver.quit() ``` - [ ] **Apply this suggestion** Suggestion importance[1-10]: 9Why: Implementing an explicit wait ensures that elements are only searched for once they are present, which significantly improves the reliability of the tests by reducing flakiness due to timing issues. | 9 |
Error handling |
Add error handling for potential exceptions during element location___ **Add error handling to catch and handle potential exceptions that may occur duringelement location, such as NoSuchElementException .**
[examples/python/tests/elements/test_locators.py [7-11]](https://github.com/SeleniumHQ/seleniumhq.github.io/pull/1903/files#diff-37a84073184f55bf24b44b3a435c07704ca453e3d74fac87370df04efec76cb8R7-R11)
```diff
+from selenium.common.exceptions import NoSuchElementException
+
driver = webdriver.Chrome()
driver.get("https://www.selenium.dev/")
-driver.find_element(By.CLASS_NAME, "td-home")
+try:
+ driver.find_element(By.CLASS_NAME, "td-home")
+except NoSuchElementException:
+ print("Element not found")
+finally:
+ driver.quit()
-driver.quit()
-
```
- [ ] **Apply this suggestion**
Suggestion importance[1-10]: 8Why: Adding error handling for exceptions like `NoSuchElementException` enhances the robustness of the test by allowing graceful handling of errors, which is crucial for reliable test execution. | 8 |
Consistency |
✅ Synchronize Python code examples across different language versions of the documentation___Suggestion Impact:The Python code examples in the Japanese documentation were updated to match the English version by adjusting line numbers. code diff: ```diff {{< tab header="Python" text=true >}} - {{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L10" >}} + {{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L9" >}} {{< /tab >}} {{< tab header="CSharp" >}} var driver = new ChromeDriver(); @@ -111,7 +111,7 @@ driver.findElement(By.cssSelector("#fname")); {{< /tab >}} {{< tab header="Python" text=true >}} - {{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L18" >}} + {{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L17" >}} {{< /tab >}} {{< tab header="CSharp" >}} var driver = new ChromeDriver(); @@ -141,7 +141,7 @@ driver.findElement(By.id("lname")); {{< /tab >}} {{< tab header="Python" text=true >}} - {{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L26" >}} + {{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L25" >}} {{< /tab >}} {{< tab header="CSharp" >}} var driver = new ChromeDriver(); @@ -172,7 +172,7 @@ driver.findElement(By.name("newsletter")); {{< /tab >}} {{< tab header="Python" text=true >}} - {{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L34" >}} + {{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L33" >}} {{< /tab >}} {{< tab header="CSharp" >}} var driver = new ChromeDriver(); @@ -201,7 +201,7 @@ driver.findElement(By.linkText("Selenium Official Page")); {{< /tab >}} {{< tab header="Python" text=true >}} - {{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L42" >}} + {{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L41" >}} {{< /tab >}} {{< tab header="CSharp" >}} var driver = new ChromeDriver(); @@ -231,7 +231,7 @@ driver.findElement(By.partialLinkText("Official Page")); {{< /tab >}} {{< tab header="Python" text=true >}} - {{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L50" >}} + {{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L49" >}} {{< /tab >}} {{< tab header="CSharp" >}} var driver = new ChromeDriver(); @@ -259,7 +259,7 @@ driver.findElement(By.tagName("a")); {{< /tab >}} {{< tab header="Python" text=true >}} - {{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L58" >}} + {{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L57" >}} {{< /tab >}} {{< tab header="CSharp" >}} var driver = new ChromeDriver(); @@ -293,7 +293,7 @@ driver.findElement(By.xpath("//input[@value='f']")); {{< /tab >}} {{< tab header="Python" text=true >}} - {{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L66" >}} + {{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L65" >}} {{< /tab >}} {{< tab header="CSharp" >}} var driver = new ChromeDriver(); @@ -318,6 +318,8 @@ all you need to do is utilize `webdriver.common.by.By`, however in others it's as simple as setting a parameter in the FindElement function +### By + {{< tabpane langEqualsHeader=true >}} {{< badge-examples >}} {{< tab header="Java" >}} @@ -326,7 +328,7 @@ driver.findElement(By.className("information")); {{< /tab >}} {{< tab header="Python" text=true >}} - {{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L10" >}} + {{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L9" >}} {{< /tab >}} {{< tab header="CSharp" >}} var driver = new ChromeDriver(); @@ -346,7 +348,59 @@ {{< /tab >}} {{< /tabpane >}} - +### ByChained + +The `ByChained` class enables you to _chain_ two By locators together. For example, instead of having to +locate a parent element, and then a child element of that parent, you can instead combine those two `FindElement` +functions into one. + +{{< tabpane langEqualsHeader=true >}} + {{< tab header="Java" text=true >}} + {{< gh-codeblock path="/examples/java/src/test/java/dev/selenium/elements/LocatorsTest.java#L37-L38" >}} + {{< /tab >}} + {{< tab header="Python" text=true >}} + {{< badge-code >}} + {{< /tab >}} + {{< tab header="CSharp" text=true >}} + {{< badge-code >}} + {{< /tab >}} + {{< tab header="Ruby" text=true >}} + {{< badge-code >}} + {{< /tab >}} + {{< tab header="JavaScript" text=true >}} + {{< badge-code >}} + {{< /tab >}} + {{< tab header="Kotlin" text=true >}} + {{< badge-code >}} + {{< /tab >}} +{{< /tabpane >}} + +### ByAll + +The `ByAll` class enables you to utilize two By locators at once, finding elements that mach _either_ of your By locators. +For example, instead of having to utilize two `FindElement()` functions to find the username and password input fields seperately, +you can instead find them together in one clean `FindElements()` + +{{< tabpane langEqualsHeader=true >}} + {{< tab header="Java" text=true >}} + {{< gh-codeblock path="/examples/java/src/test/java/dev/selenium/elements/LocatorsTest.java#L22-L23">}} + {{< /tab >}} + {{< tab header="Python" text=true >}} + {{< badge-code >}} + {{< /tab >}} + {{< tab header="CSharp" text=true >}} + {{< badge-code >}} + {{< /tab >}} + {{< tab header="Ruby" text=true >}} + {{< badge-code >}} + {{< /tab >}} + {{< tab header="JavaScript" text=true >}} + {{< badge-code >}} + {{< /tab >}} + {{< tab header="Kotlin" text=true >}} + {{< badge-code >}} + {{< /tab >}} +{{< /tabpane >}} ## 相対ロケーター @@ -382,7 +436,7 @@ By emailLocator = RelativeLocator.with(By.tagName("input")).above(By.id("password")); {{< /tab >}} {{< tab header="Python" text=true >}} -{{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L75" >}} +{{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L73" >}} {{< /tab >}} {{< tab header="CSharp" >}} var emailLocator = RelativeBy.WithLocator(By.TagName("input")).Above(By.Id("password")); @@ -408,7 +462,7 @@ By passwordLocator = RelativeLocator.with(By.tagName("input")).below(By.id("email")); {{< /tab >}} {{< tab header="Python" text=true >}} -{{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L77" >}} +{{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L75" >}} {{< /tab >}} {{< tab header="CSharp" >}} var passwordLocator = RelativeBy.WithLocator(By.TagName("input")).Below(By.Id("email")); @@ -434,7 +488,7 @@ By cancelLocator = RelativeLocator.with(By.tagName("button")).toLeftOf(By.id("submit")); {{< /tab >}} {{< tab header="Python" text=true >}} -{{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L79" >}} +{{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L77" >}} {{< /tab >}} {{< tab header="CSharp" >}} var cancelLocator = RelativeBy.WithLocator(By.tagName("button")).LeftOf(By.Id("submit")); @@ -460,7 +514,7 @@ By submitLocator = RelativeLocator.with(By.tagName("button")).toRightOf(By.id("cancel")); {{< /tab >}} {{< tab header="Python" text=true >}} -{{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L81" >}} +{{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L79" >}} {{< /tab >}} {{< tab header="CSharp" >}} var submitLocator = RelativeBy.WithLocator(By.tagName("button")).RightOf(By.Id("cancel")); @@ -488,7 +542,7 @@ By emailLocator = RelativeLocator.with(By.tagName("input")).near(By.id("lbl-email")); {{< /tab >}} {{< tab header="Python" text=true >}} -{{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L83" >}} +{{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L81" >}} {{< /tab >}} {{< tab header="CSharp" >}} var emailLocator = RelativeBy.WithLocator(By.tagName("input")).Near(By.Id("lbl-email")); @@ -513,7 +567,7 @@ By submitLocator = RelativeLocator.with(By.tagName("button")).below(By.id("email")).toRightOf(By.id("cancel")); {{< /tab >}} {{< tab header="Python" text=true >}} -{{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L85" >}} +{{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L83" >}} ```the documentation. Update the Japanese version to match the changes made in the English version.** [website_and_docs/content/documentation/webdriver/elements/locators.ja.md [81-82]](https://github.com/SeleniumHQ/seleniumhq.github.io/pull/1903/files#diff-06ad92a757672227e965b2d837608b89da6bb02315528815d9e6fa2eac9114afR81-R82) ```diff {{< tab header="Python" text=true >}} + {{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L10" >}} ``` - [ ] **Apply this suggestion** Suggestion importance[1-10]: 7Why: Ensuring consistency across language versions is important for maintaining uniformity in documentation, although it is a minor change. | 7 |
✅ Align Python code examples in the Portuguese-Brazilian documentation with the English version___Suggestion Impact:The commit updated the line numbers in the Portuguese-Brazilian documentation to align with the English version, ensuring consistency across language versions. code diff: ```diff {{< tab header="Python" text=true >}} - {{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L10" >}} + {{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L9" >}} ```made in the English version, ensuring consistency across all language versions.** [website_and_docs/content/documentation/webdriver/elements/locators.pt-br.md [84-85]](https://github.com/SeleniumHQ/seleniumhq.github.io/pull/1903/files#diff-d1f5d96e2cf4217d2473ebd28f060129cedf8bde199fc884493ffd01d205d994R84-R85) ```diff {{< tab header="Python" text=true >}} + {{< gh-codeblock path="examples/python/tests/elements/test_locators.py#L10" >}} ``` - [ ] **Apply this suggestion** Suggestion importance[1-10]: 7Why: The suggestion promotes consistency across different language versions, which is beneficial for users accessing the documentation in various languages, though it is a minor change. | 7 | |
Maintainability |
Parameterize test functions to reduce code duplication and improve maintainability___ **Consider parameterizing the test functions to reduce code duplication and make iteasier to add new test cases for different locator types.** [examples/python/tests/elements/test_locators.py [6-19]](https://github.com/SeleniumHQ/seleniumhq.github.io/pull/1903/files#diff-37a84073184f55bf24b44b3a435c07704ca453e3d74fac87370df04efec76cb8R6-R19) ```diff -def test_find_by_classname(): - driver = webdriver.Chrome() - driver.get("https://www.selenium.dev/") +@pytest.mark.parametrize("locator, value", [ + (By.CLASS_NAME, "td-home"), + (By.CSS_SELECTOR, "#announcement-banner"), + # Add more locator types and values here +]) +def test_find_element(locator, value): + with webdriver.Chrome() as driver: + driver.get("https://www.selenium.dev/") + driver.find_element(locator, value) - driver.find_element(By.CLASS_NAME, "td-home") - - driver.quit() - -def test_find_by_css_selector(): - driver = webdriver.Chrome() - driver.get("https://www.selenium.dev/") - - driver.find_element(By.CSS_SELECTOR, "#announcement-banner") - - driver.quit() - ``` - [ ] **Apply this suggestion** Suggestion importance[1-10]: 7Why: Parameterizing test functions reduces code duplication and enhances maintainability, making it easier to add new test cases and manage existing ones, although it is not as critical as resource management or error handling. | 7 |
Could I get a review please?
Thank you for the contribution @pmartinez1 ! A few changes must be made before it can be properly reviewed:
pytest import is unnecessary, pytest will not run a function if it is not prefixed by test unless explicitly called in a test function. Line 70 can be removed as well
Thanks for pointing that out. I've updated the PR.
Sorry about that, honestly forgot the relative locator section was included in this pr. I only did a cursory look through this commit's changes and commented when I saw you added an import for pytest.
Could you expand the relative locator section to have an individual test for each relative locator (above, below, rightof, leftof, and near)?
Once that's done I'll test it locally
Sorry about that, honestly forgot the relative locator section was included in this pr. I only did a cursory look through this commit's changes and commented when I saw you added an import for pytest.
Could you expand the relative locator section to have an individual test for each relative locator (above, below, rightof, leftof, and near)?
Once that's done I'll test it locally
No problem. And yes, will split them up.
Sorry about that, honestly forgot the relative locator section was included in this pr. I only did a cursory look through this commit's changes and commented when I saw you added an import for pytest. Could you expand the relative locator section to have an individual test for each relative locator (above, below, rightof, leftof, and near)? Once that's done I'll test it locally
No problem. And yes, will split them up.
I ended updating them a bit more. Originally, I had created the test not to run, but follow along with the static image that is present, but I think your approach is better. I borrowed a little from your PR (for the sake of expediency) and now the tests are ready to be run.
Use what's available, I don't mind. I'll pull the branch for test
Tested changes locally and looks good. The goal is to move all the code examples to executable files in the repo, so eventually this whole section on relative locators will eventually be refactored to no longer refer to that image.
What do you think about this PR? @harsha509
Hi @harsha509,
Would you be able to give this a review? @shbenzer has already given it one pass.
Thank you.
Wow. Again tests are failing on my PR :(
For some reason, the "test_find_by_link_text" test is failing on Windows only, but seems to be deterministic. Does anyone have a Windows machine they can test on? Any ideas? I can't think of a reason why it fails there or at all. The test is simply going to the Selenium and looking for "Documentation". It passes in every other environment and a similar test, "test_find_by_partial_link_text" passes with no issue everywhere.
I could add waits to see if it is a timing/loading issue?
I haven't gotten around to finding an option for testing Windows yet, but it is on my list.
User description
Thanks for contributing to the Selenium site and documentation! A PR well described will help maintainers to review and merge it quickly
Before submitting your PR, please check our contributing guidelines. Avoid large PRs, and help reviewers by making them as simple and short as possible.
Description
This PR moves the code to the test_locators.py file in the python/tests directory.
Motivation and Context
Helps the code be more organized, instead of having stand alone code that has not been tested.
Types of changes
Checklist
PR Type
Tests, Documentation
Description
Changes walkthrough 📝
test_locators.py
Add test cases for various Selenium locators in Python
examples/python/tests/elements/test_locators.py
partial link text, tag name, and XPath.
locators.en.md
Update Python locator examples to reference test file
website_and_docs/content/documentation/webdriver/elements/locators.en.md
locators.ja.md
Update Python locator examples to reference test file
website_and_docs/content/documentation/webdriver/elements/locators.ja.md
locators.pt-br.md
Update Python locator examples to reference test file
website_and_docs/content/documentation/webdriver/elements/locators.pt-br.md
locators.zh-cn.md
Update Python locator examples to reference test file
website_and_docs/content/documentation/webdriver/elements/locators.zh-cn.md