{"id":26336929,"url":"https://github.com/actmd/elementium","last_synced_at":"2025-03-16T02:16:47.463Z","repository":{"id":46217346,"uuid":"21390522","full_name":"actmd/elementium","owner":"actmd","description":"jQuery-style syntactic sugar for highly reliable automated browser testing in Python","archived":false,"fork":false,"pushed_at":"2021-11-06T06:28:45.000Z","size":73,"stargazers_count":59,"open_issues_count":8,"forks_count":19,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-03-15T19:18:56.196Z","etag":null,"topics":["browser-testing","python","selenium","selenium-python-bindings"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/actmd.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-07-01T14:23:01.000Z","updated_at":"2025-02-27T07:09:54.000Z","dependencies_parsed_at":"2022-09-26T18:30:28.517Z","dependency_job_id":null,"html_url":"https://github.com/actmd/elementium","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/actmd%2Felementium","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/actmd%2Felementium/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/actmd%2Felementium/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/actmd%2Felementium/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/actmd","download_url":"https://codeload.github.com/actmd/elementium/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243814895,"owners_count":20352038,"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":["browser-testing","python","selenium","selenium-python-bindings"],"created_at":"2025-03-16T02:16:46.996Z","updated_at":"2025-03-16T02:16:47.454Z","avatar_url":"https://github.com/actmd.png","language":"Python","readme":"Elementium\n==========\n![](https://travis-ci.org/actmd/elementium.svg?branch=master)\n\n[http://github.com/actmd/elementium](http://github.com/actmd/elementium)\n\njQuery-style syntactic sugar for highly reliable automated browser testing in Python\n\n* Chainable methods with obvious names\n* Easy to read\n* Concise to write\n* Built-in fault tolerance\n\nFor an introduction to why you'd want to use Elementium, take a look at [the following post](http://prschmid.blogspot.com/2014/07/elementium-browser-testing-done-right.html).\n\nBefore \u0026 After\n--------------\n\n### With only the [Selenium Python Bindings](http://selenium-python.readthedocs.org/en/latest/index.html)\n\n```python\n# From http://selenium-python.readthedocs.org/en/latest/getting-started.html\n\nfrom selenium import webdriver\nfrom selenium.webdriver.common.keys import Keys\n\ndriver = webdriver.Firefox()\ndriver.get(\"http://www.python.org\")\nassert \"Python\" in driver.title\nelem = driver.find_element_by_name(\"q\")\nelem.send_keys(\"selenium\")\nelem.send_keys(Keys.RETURN)\ndriver.close()\n```\n\n### With Elementium\n\n```python\nfrom selenium import webdriver\nfrom selenium.webdriver.common.keys import Keys\nfrom elementium.drivers.se import SeElements\n\nse = SeElements(webdriver.Firefox())\nse.navigate(\"http://www.python.org\").insist(lambda e: \"Python\" in e.title)\nse.find(\"q\").write(\"selenium\" + Keys.RETURN)\n\n```\n\nInstallation\n------------\n\n### The easy way\n\n```sh\npip install elementium\n```\n\n### The developer way\n\n```sh\ngit clone git@github.com:actmd/elementium.git\ncd elementium\npython setup.py install\n```\n\nCompatability\n-------------\n\nElementium has been tested for Python 2.6, 3.4, 3.5, 3.7, and pypy using [Travis CI](https://travis-ci.org/actmd/elementium)\n\nUsage\n-----\n\nElementium includes by default a wrapper for the [Selenium Python Bindings](http://selenium-python.readthedocs.org/en/latest/api.html). As such, all of the usage examples make use of the Selenium driver.\n\n### Wrap the browser with an Elementium object\n\n```python\nfrom selenium import webdriver\nfrom elementium.drivers.se import SeElements\n\nse = SeElements(webdriver.Firefox())\n```\n\n### Navigating to a web page\n\n```python\nse.navigate(\"http://www.google.com\")\n```\n\n### Finding DOM elements\n\nElementium simplifies most of Selenium's many `find` methods...\n\n* `find_element_by_id`\n* `find_element_by_name`\n* `find_element_by_tag_name`\n* `find_element_by_class_name`\n* `find_element_by_css_selector`\n* `find_element_by_link_text`\n* `find_element_by_partial_link_text`\n\n...into two `find()` and `find_link()` methods:\n\n```python\n# Find by ID\nse.find(\"#foo\")\n\n# Find by name\nse.find(\"[name='foo']\")\n\n# Find by tag name\nse.find(\"input\")\n\n# Find by class name\nse.find(\".cssClass\")\n\n# Find by link text\nse.find_link(\"Click me\")\n\n# Find by partial link text\nse.find_link(\"Click\", exact=False)\n```\n\n`find()` and `find_link()` will also return multiple elements, if present, so you can forget about all the additional `find_elements_...` methods, too:\n\n```html\n\u003cdiv\u003e...\u003c/div\u003e \u003cdiv\u003e...\u003c/div\u003e \u003cdiv\u003e...\u003c/div\u003e\n```\n\n```python\nlen(se.find(\"div\")) # == 3\n```\n\nUnder the hood, `find()` returns a new `SeElements` object containing a list of all of the items that matched. (These individual items are also of type `SeElements`.)\n\n### Getting specific items\n\nThe `get` method lets you pull out a specific item in a chainable manner.\n\n```html\n\u003cbutton\u003eFoo\u003c/button\u003e \u003cbutton\u003eBar\u003c/button\u003e \u003cbutton\u003eBaz\u003c/button\u003e\n```\n\n```python\n# Get the second button\nse.find(\"button\").get(1)\n```\n\n#### Accessing the raw object\n\nIf you would rather get the raw object (e.g. `SeleniumWebElement`) that is returned by the underlying driver, use `items`:\n\n```python\n# Find elements on a page for a given class\nbuttons = se.find(\"button\")\nfor button in buttons.items:\n    print type(button)\n```\n\nThe `item` alias will return the *first* raw item:\n\n```python\nse.find(\"button\").item\n```\n\n### Getting values\n\n```html\n\u003cinput value=\"blerg\" /\u003e\n```\n\n```python\nse.find(\"input\").value() # returns 'blerg'\n```\n\n### Clicking things\n\n```html\n\u003cbutton\u003eClick me\u003c/button\u003e\n```\n\n```python\nse.find(\"button\").click()\n```\n\n```html\n\u003cinput type=\"checkbox\" value=\"check1\"\u003e\n\u003cinput type=\"checkbox\" value=\"check2\"\u003e\n\u003cinput type=\"checkbox\" value=\"check3\"\u003e\n```\n\n```python\n# Click all three checkboxes\nse.find(\"input[type='checkbox']\").click()\n```\n\n### Typing\n\n```html\n\u003cinput type=\"text\" /\u003e\n```\n\n```python\nse.find(\"input\").write(\"If not now, when?\")\n```\n\n### Selecting\n\n```html\n\u003cselect\u003e\n    \u003coption value=\"cb\"\u003eCorned Beef\u003c/option\u003e\n    \u003coption value=\"ps\"\u003ePastrami\u003c/option\u003e\n\u003c/select\u003e\n```\n\n```python\n# Select by visible text\nse.find(\"select\").select(text=\"Corned Beef\")\n\n# Select by value\nse.find(\"select\").select(value=\"cb\")\n\n# Select by index\nse.find(\"select\").select(i=0)\n```\n\nIf manipulating a multiple select, you may use the `deselect()` method in a similar manner:\n\n```html\n\u003cselect multiple\u003e\n    \u003coption value=\"h\"\u003eHummus\u003c/option\u003e\n    \u003coption value=\"t\"\u003eTahina\u003c/option\u003e\n    \u003coption value=\"c\"\u003eChips\u003c/option\u003e\n    \u003coption value=\"a\"\u003eAmba\u003c/option\u003e\n\u003c/select\u003e\n```\n\n```python\n# Deselect by visible text\nse.find(\"select\").deselect(text=\"Chips\")\n\n# Deelect by value\nse.find(\"select\").deselect(value=\"c\")\n\n# Deselect by index\nse.find(\"select\").deselect(i=2)\n\n# Deselect all\nse.find(\"select\").deselect()\n```\n\n\n### Waiting\n\nSo far, we haven't taken any huge leaps from off-the-shelf Selenium, though we're certainly typing less!\n\nOne of the big issues with Selenium is waiting for pages to load completely and all of the retry logic that may have to be used to have tests that work well. A common solution is to [wrap your code with \"retry\" functions](https://saucelabs.com/resources/selenium/lose-races-and-win-at-selenium).\n\nFor example, a naive way of retrying might have been:\n\n```python\nbrowser = webdriver.Firefox()\nels = None\nwhile not els:\n    els = browser.find_element_by_tag_name('button')\n    time.sleep(0.5)\n```\n\nWith Elementium, just tell `find()` to wait:\n\n```python\n# Retry until we find a button on the page (up to 20 seconds by default)\nse.find('button', wait=True)\n```\n\nHave a more complex success condition? Use `until()`:\n\n```python\n# Retry until we find 3 buttons on the page (up to 20 seconds by default)\nse.find('button').until(lambda e: len(e) == 3)\n\n# Retry for 60 seconds\nse.find('button').until(lambda e: len(e) == 3, ttl=60)\n```\n\nBoth of the above methods will raise a ``elementium.elements.TimeoutError`` if the element is not found in the specified period of time.\n\nBasically all methods that are part of the `SeElements` object will be automatically retried for you. Under the hood, each selector (e.g. '.foo' or '#foo') is stored as a callback function (similar to something like ``lambda: selenium.find_element_by_id('foo')``). This way, when any of the calls to any of the methods of an element has an expected error (``StaleElementException``, etc.) it will recall this function. If you perform chaining, this will actually propagate that refresh (called ``update()``) up the entire chain to ensure that all parts of the call are valid. Cool!\n\n(Look at the code for more detail.)\n\n\n### Making assertions\n\n```python\nse.find('input').insist(lambda e: e.value() == 'Pilkington')\n```\n\nThis works exactly like `until()` above, only it raises an ``AssertionError`` instead.\n\n### Other useful methods\n\nSee the full Elementium documentation for more details on the following methods.\n\n* `filter()`\n* `scroll()`\n* `scroll_top()`\n* `scroll_bottom()`\n\nThe following are simply more reliable versions of their Selenium counterparts. Some have been renamed for ease of use.\n\n* `is_displayed()`\n* `is_enabled()`\n* `is_selected()`\n* `text()`\n* `tag_name()`\n* `attribute()`\n* `clear()`\n* `parent()`\n* `xpath()`\n* `source()`\n* `refresh()`\n* `current_url()`\n* `execute_script()`\n* `get_window_size()`\n* `set_window_size()`\n* `switch_to_active_element()`\n\nExamples\n--------\n\nThere are a couple examples in the aptly named examples directory. Take a look there for fully functioning source code.\n\nRunning the Tests\n-----------------\n\n### Simple\n\nFirst, make sure to install the testing requirements\n\n```sh\npip install -r requirements-tests.txt\n```\n\nThen run the tests via nose\n\n```sh\nnosetests\n```\n\n### Running the tests across multiple python versions in parallel\n\nIf you don't trust our Travis CI badge above, you can run all of the tests across multiple python versions by using [pyenv](https://github.com/yyuu/pyenv) and [detox](https://pypi.python.org/pypi/detox). A good writeup for what you need to do to set this up can be found [here](http://blog.pinaxproject.com/2015/12/08/how-test-against-multiple-python-versions-parallel/). If you are using OS X and installed pyenv with brew, make sure to follow [these instructions](https://github.com/yyuu/pyenv#homebrew-on-mac-os-x) as well.\n\n```sh\n# Assuming OS X with Homebrew installed\nbrew update\nbrew install pyenv\n```\n\n```sh\n# Install tox and detox\npip install tox\npip install detox\n```\n\nYou'll want to make sure that you have all of the different python versions are installed so that they can be tested:\n\n```sh\n# Install the pyenv versions\npyenv install 2.7.13\npyenv install 3.4.7\npyenv install 3.5.4\npyenv install 3.6.0\npyenv install 3.7.3\n\n# Set all these to be global versions\npyenv global system 2.7.13 3.4.7 3.5.4 3.6.0 3.7.3\n\n# Make sure that they are all there (they should all have a * next to them)\npyenv versions\n```\n\nNote, if you are running in to issues installing python due to a `zlib` issue, then take a look at [the solution in this thread](https://github.com/pyenv/pyenv/issues/1219) which can be summarized by saying that you should install your pyenv versions as follows\n\n```\nCFLAGS=\"-I$(xcrun --show-sdk-path)/usr/include\" before your pyenv install ...\n```\n\nOnce you get everything installed, you can run the tests across the different versions as follows.\n\n```sh\ndetox\n```\n\nNote this assumes that you have detox installed globally.\n\nAssuming all goes well, you should see a result akin to\n\n```sh\npy27-1.7: commands succeeded\npy27-1.8: commands succeeded\npy27-1.9: commands succeeded\npy27-master: commands succeeded\npy34-1.7: commands succeeded\npy34-1.8: commands succeeded\npy34-1.9: commands succeeded\npy34-master: commands succeeded\npy35-1.8: commands succeeded\npy35-1.9: commands succeeded\npy35-master: commands succeeded\ncongratulations :)\n```\n\nIf you run in to an issue with running detox, make sure that you have the latest version of pip as there are [some issues](https://github.com/yyuu/pyenv/issues/531) with pyenv and older versions of pip.\n\nThe Future\n----------\n\nThere are several features planned for the future to improve Elementium and they will be rolled out as they pass through our internal scrutiny. If you have great ideas, you can be part of Elementium's future as well!\n\nContributing\n------------\n\nIf you would like to contribute to this project, you will need to use [git flow](https://github.com/nvie/gitflow). This way, any and all changes happen on the development branch and not on the master branch. As such, after you have git-flow-ified your elementium git repo, create a pull request for your branch, and we'll take it from there.\n\nAcknowledgements\n----------------\n\nElementium has been a collaborative effort of [ACT.md](http://act.md).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Factmd%2Felementium","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Factmd%2Felementium","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Factmd%2Felementium/lists"}