{"id":20721619,"url":"https://github.com/fslev/selenium-jutils","last_synced_at":"2025-04-23T15:14:46.745Z","repository":{"id":37835579,"uuid":"388165227","full_name":"fslev/selenium-jutils","owner":"fslev","description":"Selenium Java Utils","archived":false,"fork":false,"pushed_at":"2025-04-02T22:21:58.000Z","size":151,"stargazers_count":3,"open_issues_count":10,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-23T15:14:40.578Z","etag":null,"topics":["java","polling","retry","selenium","webcontext"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fslev.png","metadata":{"files":{"readme":"Readme.md","changelog":"Changelog.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-07-21T15:38:42.000Z","updated_at":"2024-07-22T17:31:16.000Z","dependencies_parsed_at":"2023-11-07T16:28:19.673Z","dependency_job_id":"d1ab9808-de67-4d18-9784-5d6dc5f43a6d","html_url":"https://github.com/fslev/selenium-jutils","commit_stats":null,"previous_names":[],"tags_count":26,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fslev%2Fselenium-jutils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fslev%2Fselenium-jutils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fslev%2Fselenium-jutils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fslev%2Fselenium-jutils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fslev","download_url":"https://codeload.github.com/fslev/selenium-jutils/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250457792,"owners_count":21433734,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["java","polling","retry","selenium","webcontext"],"created_at":"2024-11-17T03:28:43.194Z","updated_at":"2025-04-23T15:14:46.720Z","avatar_url":"https://github.com/fslev.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Selenium JUtils \u003csup\u003e[![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://vshymanskyy.github.io/StandWithUkraine)\n\u003c/sup\u003e\n\n[![Maven Central](https://img.shields.io/maven-central/v/io.github.fslev/selenium-jutils.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22io.github.fslev%22%20AND%20a:%22selenium-jutils%22)\n![Build status](https://github.com/fslev/selenium-jutils/workflows/Java%20CI%20with%20Maven/badge.svg?branch=main)\n[![Coverage Status](https://coveralls.io/repos/github/fslev/selenium-jutils/badge.svg?branch=main)](https://coveralls.io/github/fslev/selenium-jutils?branch=main)\n\nA light Java library designed to tackle the shortcomings of Selenium Page Object Model and Page Factory features.  \nIt provides the following enhancements:\n- __WebContext__, used for locating web elements relative to the parent search context  \n- __Retry on error mechanism__, activated when a specific error or exception occurs while locating and interacting with a web element, such as StaleElementReferenceException.  \n\n### Maven Central\n```\n\u003cdependency\u003e\n   \u003cgroupId\u003eio.github.fslev\u003c/groupId\u003e\n   \u003cartifactId\u003eselenium-jutils\u003c/artifactId\u003e\n   \u003cversion\u003e${latest.version}\u003c/version\u003e\n\u003c/dependency\u003e\n\nGradle: compile(\"io.github.fslev:selenium-jutils:${latest.version}\")\n```  \n\n### Required dependencies\nSelenium-JUtils uses the _selenium-java_ library. Set it inside your project, in addition to _selenium-jutils_ dependency:  \n```\n\u003cdependency\u003e\n   \u003cgroupId\u003eorg.seleniumhq.selenium\u003c/groupId\u003e\n   \u003cartifactId\u003eselenium-java\u003c/artifactId\u003e\n   \u003cversion\u003e${selenium.java.version}\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n# How to use\nDecorate your Page Object class instance using PageFactory and FieldContextDecorator:  \n```java\npublic class BasePage {\n    protected WebDriver driver;\n\n    public BasePage(WebDriver driver) {\n        this.driver = driver;\n        PageFactory.initElements(new FieldContextDecorator(new ElementContextLocatorFactory(driver)), this);\n    }\n}\n```\n\n# Features\n\n## WebContext\nYou can group WebElements or other context classes under the same class which extends WebContext and each element will be located relative to the search context of its wrapper class.  \n__Example:__\n\n```java\npublic class GroceryPage extends BasePage {\n\n    @FindBy(xpath = \"//app-list\")\n    private GroceryListTab groceryListTab;\n}\n\npublic class GroceryListTab extends WebContext {\n\n    @FindBy(xpath = \".//li//app-item\")\n    private List\u003cItem\u003e items;\n}\n\npublic class Item extends WebContext {\n    \n    @FindBy(css = \"span\")\n    private WebElement name;\n    @FindBy(xpath = \".//button[text()='Remove']\")\n    private WebElement removeButton;\n} \n```\nSee how easy is to manage a grocery list:\n```java\nGroceryPage groceryPage = new GroceryPage(driver);\nList\u003cItem\u003e itemList = groceryPage.getGroceryListTab().getItems();\n\nassertEquals(6, itemList.size());\nassertEquals(\"Baking item1\", itemList.get(0).getName().getText());\n// Remove 4th item\nlist.get(3).getRemoveButton().click();\nassertEquals(5, itemList.size());\n```\n__Behind the scenes__\n```java\nnew GroceryPage(driver).getGroceryListTab().getItems().get(2).getName()\n```\n==\u003e\n```java\ndriver.findElement(By.xpath(\"//app-list\"))\n        .findElements(By.xpath(\".//li//app-item\"))\n          .get(2)\n            .findElement(By.cssSelector(\"span\"))\n```\nBehind the scenes, the web element(s) you get, are nothing but Java proxies which are first locating the corresponding element every time you interact with it.\nIt preserves the default behaviour and features of Selenium Page Factory: https://github.com/SeleniumHQ/selenium/wiki/PageFactory\n\n## Retry on error\nThere is a possibility that after locating a web element(s) but before interacting with it, the DOM gets refreshed, in which case you will receive a _StaleElementReferenceException_.  \n```java\nnew GroceryPage(driver).getGroceryListTab().getItems().get(2)\n        // \u003c-- DOM is refreshed\n        .getName()\n```\nor\n```java\ndriver.findElement(By.xpath(\"//app-list\"))\n        .findElements(By.xpath(\".//li//app-item\"))\n          .get(2)\n            // \u003c-- DOM is refreshed \n            .findElement(By.cssSelector(\"span\"))\n```\n=\u003e _StaleElementReferenceException_  \n\nOr maybe the element cannot be selected for a very short period of time, in which case you get _ElementNotSelectableException_.\n\nThe __retry on error__ mechanism tackles these problems by invoking again the chained localisation and interaction of the web element, if any specific error occurs.\nIn order to activate it, instantiate the _ElementContextLocatorFactory_ with a specific List of errors or exceptions, upon which web element localisation and interaction should be retried, and a duration timeout. \n```java\nPageFactory.initElements(new FieldContextDecorator(new ElementContextLocatorFactory(\n                driver, Duration.ofSeconds(20), Arrays.asList(StaleElementReferenceException.class, \n                    ElementNotSelectableException.class ))), this);\n\n```\n\n## In detail...\nPlease take a look over the project tests in order to get a clearer picture on how the WebContext and Retry on error mechanism work.  \nYou need to start Selenium Grid and the Grocery application via docker compose, from _src/test/resources_:\n```\ndocker-compose -f selenium-grid.yml up\n```\n\n## Showcase\nThis [**tutorial**](https://github.com/fslev/cucumber-selenium-tutorial)\nshows you how to test a website user interface with Selenium and Cucumber for Java\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffslev%2Fselenium-jutils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffslev%2Fselenium-jutils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffslev%2Fselenium-jutils/lists"}