{"id":15009444,"url":"https://github.com/testlabauto/local_selenium_pool","last_synced_at":"2026-03-01T11:31:50.858Z","repository":{"id":62576579,"uuid":"137121596","full_name":"testlabauto/local_selenium_pool","owner":"testlabauto","description":"A local python selenium pool for increased testing performance without requiring multiple hosts.","archived":false,"fork":false,"pushed_at":"2018-06-25T14:51:16.000Z","size":251,"stargazers_count":19,"open_issues_count":1,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-12-01T10:39:46.754Z","etag":null,"topics":["automation","multiprocessing","python-3-6","qa","qa-automation-test","selenium","testing"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/testlabauto.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-06-12T20:02:31.000Z","updated_at":"2024-06-06T18:13:52.000Z","dependencies_parsed_at":"2022-11-03T19:04:16.057Z","dependency_job_id":null,"html_url":"https://github.com/testlabauto/local_selenium_pool","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/testlabauto/local_selenium_pool","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/testlabauto%2Flocal_selenium_pool","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/testlabauto%2Flocal_selenium_pool/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/testlabauto%2Flocal_selenium_pool/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/testlabauto%2Flocal_selenium_pool/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/testlabauto","download_url":"https://codeload.github.com/testlabauto/local_selenium_pool/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/testlabauto%2Flocal_selenium_pool/sbom","scorecard":{"id":875191,"data":{"date":"2025-08-11","repo":{"name":"github.com/testlabauto/local_selenium_pool","commit":"224b6da6400fa11cf56f0e37005da8bd7e7a113c"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.3,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Binary-Artifacts","score":3,"reason":"binaries present in source code","details":["Warn: binary detected: local_selenium_pool/__pycache__/__init__.cpython-36.pyc:1","Warn: binary detected: local_selenium_pool/__pycache__/decorator.cpython-36.pyc:1","Warn: binary detected: local_selenium_pool/__pycache__/output_parser.cpython-36.pyc:1","Warn: binary detected: local_selenium_pool/__pycache__/output_queue.cpython-36.pyc:1","Warn: binary detected: local_selenium_pool/__pycache__/pool.cpython-36.pyc:1","Warn: binary detected: local_selenium_pool/__pycache__/selenium_worker.cpython-36.pyc:1","Warn: binary detected: local_selenium_pool/__pycache__/test_case.cpython-36.pyc:1"],"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE.txt:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE.txt:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":4,"reason":"6 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: PYSEC-2022-43167","Warn: Project is vulnerable to: PYSEC-2023-206","Warn: Project is vulnerable to: PYSEC-2013-22 / GHSA-27x4-j476-jp5f","Warn: Project is vulnerable to: PYSEC-2025-49 / GHSA-5rjg-fvgr-3xxf","Warn: Project is vulnerable to: GHSA-cx63-2mw6-8hw5","Warn: Project is vulnerable to: PYSEC-2022-43012 / GHSA-r9hx-vwmv-q579"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-24T05:42:26.421Z","repository_id":62576579,"created_at":"2025-08-24T05:42:26.421Z","updated_at":"2025-08-24T05:42:26.421Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29968462,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-01T10:55:55.490Z","status":"ssl_error","status_checked_at":"2026-03-01T10:55:55.175Z","response_time":124,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["automation","multiprocessing","python-3-6","qa","qa-automation-test","selenium","testing"],"created_at":"2024-09-24T19:25:17.388Z","updated_at":"2026-03-01T11:31:50.841Z","avatar_url":"https://github.com/testlabauto.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# local_selenium_pool (Python)\n\n\n\nA local selenium pool for increased testing performance without requiring multiple hosts.    multiprocessing-on-dill is used to provide a configurable number of Chrome webdriver instances on which to simultaneously run selenium tests.   Each instance reuses its _applicationCacheEnabled = False_ webdriver for multiple tests, erasing all cookies between tests.\n\nThis project includes a sample test that depends an awesome free resource called [automationpractice.com](http://automationpractice.com/index.php) which is a full featured web store sandbox.  Much thanks to [StMarco89](https://github.com/StMarco89/automationpractice.com)!  \n\nThe sample test [test_pool.py](https://github.com/testlabauto/local_selenium_pool/blob/master/test_pool.py), has nine tests in it which can be executed using any number of processes reading from the same queue of tests.  Each test searches the site's products for a different keyword.  It then adds each item found to the cart, one at a time.  Finally, it goes to the checkout page and compares the expected total to the basket total.\n\n![Performance Gain](https://github.com/testlabauto/local_selenium_pool/blob/master/images/pyloselpo_perf.png)\n\nAfter the pool of webdrivers has no remaining tests to execute, it creates a JSON report in an XUnit style. \n\n\u003cdetails\u003e\n  \u003csummary\u003eClick to expand sample output\u003c/summary\u003e\n  \u003cp\u003e\n\u003c!-- the above p cannot start right at the beginning of the line and is mandatory for everything else to work --\u003e\n\n```python\n{\n    \"tests\": 9,\n    \"passed\": 7,\n    \"errors\": 1,\n    \"failed\": 1,\n    \"testcase\": [\n        [\n            {\n                \"function\": \"test_url1\",\n                \"process_id\": 47455,\n                \"stdout\": \"[2018-06-22 13:03:41] Starting test_url1\\n[2018-06-22 13:04:17] dress 7\\n[2018-06-22 13:04:17] Finished test_url1\",\n                \"passed\": false,\n                \"time\": \"2018-06-22 13:03:41\",\n                \"duration\": \"36.0\",\n                \"assertion\": local_selenium_pool\n            },\n            {\n                \"function\": \"test_url3\",\n                \"process_id\": 47454,\n                \"stdout\": \"[2018-06-22 13:03:41] Starting test_url3\\n[2018-06-22 13:03:59] blouse 1\\n[2018-06-22 13:04:01] blouse $29.00\\n[2018-06-22 13:04:01] Finished test_url3\",\n                \"passed\": true,\n                \"time\": \"2018-06-22 13:03:41\",\n                \"duration\": \"20.0\"\n            },\n            {\n                \"function\": \"test_url8\",\n                \"process_id\": 47454,\n                \"stdout\": \"[2018-06-22 13:04:01] Starting test_url8\\n[2018-06-22 13:04:17] straps 2\\n[2018-06-22 13:04:20] straps $47.38\\n[2018-06-22 13:04:20] Finished test_url8\",\n                \"passed\": true,\n                \"time\": \"2018-06-22 13:04:01\",\n                \"duration\": \"19.0\"\n            },\n            {\n                \"function\": \"test_url6\",\n                \"process_id\": 47452,\n                \"stdout\": \"[2018-06-22 13:03:41] Starting test_url6\\n[2018-06-22 13:03:56] popular 0\\n[2018-06-22 13:03:56] Finished test_url6\",\n                \"passed\": true,\n                \"time\": \"2018-06-22 13:03:41\",\n                \"duration\": \"15.0\"\n            },\n            {\n                \"function\": \"test_url7\",\n                \"process_id\": 47452,\n                \"stdout\": \"[2018-06-22 13:03:56] Starting test_url7\\n[2018-06-22 13:04:09] faded 1\\n[2018-06-22 13:04:11] faded $18.51\\n[2018-06-22 13:04:11] Finished test_url7\",\n                \"passed\": false,\n                \"time\": \"2018-06-22 13:03:56\",\n                \"duration\": \"15.0\",\n                \"error\": local_selenium_pool\n            },\n            {\n                \"function\": \"test_url2(test=2)\",\n                \"process_id\": 47461,\n                \"stdout\": \"[2018-06-22 13:03:41] Starting test_url2(test=2)\\n[2018-06-22 13:04:05] chiffon 2\\n[2018-06-22 13:04:07] chiffon $48.90\\n[2018-06-22 13:04:07] Finished test_url2\",\n                \"passed\": true,\n                \"time\": \"2018-06-22 13:03:41\",\n                \"duration\": \"26.0\"\n            },\n            {\n                \"function\": \"test_url9\",\n                \"process_id\": 47461,\n                \"stdout\": \"[2018-06-22 13:04:07] Starting test_url9\\n[2018-06-22 13:04:17] evening 1\\n[2018-06-22 13:04:20] evening $52.99\\n[2018-06-22 13:04:20] Finished test_url9\",\n                \"passed\": true,\n                \"time\": \"2018-06-22 13:04:07\",\n                \"duration\": \"13.0\"\n            },\n            {\n                \"function\": \"test_url4\",\n                \"process_id\": 47453,\n                \"stdout\": \"[2018-06-22 13:03:42] Starting test_url4\\n[2018-06-22 13:04:15] printed 5\\n[2018-06-22 13:04:18] printed $154.87\\n[2018-06-22 13:04:18] Finished test_url4\",\n                \"passed\": true,\n                \"time\": \"2018-06-22 13:03:42\",\n                \"duration\": \"36.0\"\n            },\n            {\n                \"function\": \"test_url5\",\n                \"process_id\": 47459,\n                \"stdout\": \"[2018-06-22 13:03:42] Starting test_url5\\n[2018-06-22 13:04:13] summer 4\\n[2018-06-22 13:04:15] summer $94.39\\n[2018-06-22 13:04:15] Finished test_url5\",\n                \"passed\": true,\n                \"time\": \"2018-06-22 13:03:42\",\n                \"duration\": \"33.0\"\n            }\n        ]\n    ],\n    \"host\": \"ChristophersMacmini.longmontcolorado.gov\",\n    \"duration\": 41.14260005950928,\n    \"name\": \"test_pool\",\n    \"time\": \"2018-06-22 13:04:20\"\n}\n```\n\u003c/p\u003e\u003c/details\u003e\n\n\n## Multiprocessing on Dill\n\nMultiprocessing is used instead of multithreading or gevent in order to best isolate each selenium instance in a pool from the other instances.  Multiprocessing on Dill is used for compatibility with attr (to avoid pickling errors when using decorators).\n\n## Input and Output Queues\n\nThe Selenium executor processes share the same input and outputs.  On the input side, they get test cases from a JoinableQueue and exit when that queue is empty.  On the output side, they print() output and log exceptions and assertions to queues to avoid sharing resources.  When the input queue is empty and all the processes exit their main loop, the data from the queues is processed into a readable report.\n\n![Overview](https://github.com/testlabauto/local_selenium_pool/blob/master/images/pyloselpo.png)\n\n## Decorators\nDecorators are required on test cases.  The _@sel_pool()_ decorator allows for stdout/stderr redirection and for the appropriate web driver to be provided to the test.  Additionally, test cases can be data driven using the decorator's parameter, **kwargs.\n\nWhen adding tests to the queue with auto_fill_queue(), the decorator can be parameterized like this:  \n\n    @sel_pool(**{'test': 2, 'test2': 5.6})\n\nWhen adding tests to the queue with a put() to the JoinableQueue, parameters can be provided like this: \n\n    input_queue.put((test_url2, {'test': 2}))\n\n## Getting Started\n\n### Prerequisites\nThis project requires Python 3.6.  \n\nI have only tested this on OS X so far, but welcome feedback from anyone working on Windows.  I plan to test on Windows soon.\n\n### Installing\n#### Clone project\n\n1) Create a Python 3.6 virtualenv\n2) Clone the project and run pip install -r requirements.txt \n3) Download chromedriver and put it in your PATH\n\n#### pip\n1) Create a Python 3.6 virtualenv\n2) pip install local_selenium_pool\n3) Create a python file and copy the contents of the file  [test_pool.py](https://github.com/testlabauto/local_selenium_pool/blob/master/test_pool.py) into it\n3) Download chromedriver and put it in your PATH\n\n\n## Running the sample test, test_pool.py\n* Run the script (test_pool.py) several times, varying the _processes_ parameter to create_pool().  The default, shown below, is 6.\n* Comment out the input_queue.put() lines and uncomment the auto_fill_queue() line.  These are the two alternative ways to add tests to the pool\n\n```\nif __name__ == \"__main__\":\n\n    start = time.time()\n\n    chrome_options = Options()\n    chrome_options.add_argument(\"--headless\")\n\n    input_queue, output_queue = create_pool(os.path.splitext(os.path.basename(__file__))[0],\n                                            chrome_options,\n                                            processes=6)\n\n\n    #auto_fill_queue(sys.modules[__name__], input_queue, 'test_')\n\n    input_queue.put((test_url1))\n    input_queue.put((test_url2, {'test': 2}))\n    input_queue.put((test_url3))\n    input_queue.put((test_url4,))\n    input_queue.put((test_url5))\n    input_queue.put((test_url6))\n    input_queue.put((test_url7))\n    input_queue.put((test_url8))\n    input_queue.put((test_url9))\n\n    report = wait_for_pool_completion(input_queue)\n\n    print(report)\n```\n\n## Test Cases\n\nThere are two requirements for testcases:\n* Use the **kwargs argument (you will access the driver and your own parameters via kwargs)\n* Use the @sel_pool() decorator (parameters optional)\n```python\n@sel_pool(**{'test': 2})\ndef test_something(**kwargs):\n    assert kwargs.pop('test') == 2\n```\n\n\u003cdetails\u003e\n  \u003csummary\u003eClick to see more sample test case code\u003c/summary\u003e\n  \u003cp\u003e\n\u003c!-- the above p cannot start right at the beginning of the line and is mandatory for everything else to work --\u003e\n\n```python\n\ndef body(driver, subject):\n    driver.get(\"http://automationpractice.com/\")\n    time.sleep(1)\n    input_element = driver.find_element_by_name(\"search_query\")\n    input_element.send_keys(subject)\n    input_element.submit()\n\n    pic = 'product-image-container'\n    time.sleep(2)\n\n    image_containers = driver.find_elements_by_class_name(pic)\n    images = []\n    for container in image_containers:\n        images.extend(container.find_elements_by_class_name('replace-2x'))\n\n    counter = 0\n    cart_added = 0\n    for image in images:\n\n        hover = ActionChains(driver).move_to_element(image)\n        hover.perform()\n\n        add_to_cart = 'ajax_add_to_cart_button'\n        time.sleep(2)\n\n        add_to_cart = driver.find_elements(By.CLASS_NAME, add_to_cart)[counter]\n        counter += 1\n        try:\n            add_to_cart.click()\n\n            continue_shopping = 'continue'\n\n            WebDriverWait(driver, 10).until(\n                EC.visibility_of_element_located((By.CLASS_NAME, continue_shopping)))\n\n            continue_button = driver.find_element(By.CLASS_NAME, continue_shopping)\n\n            continue_button.click()\n            cart_added += 1\n        except Exception as e:\n            print(e)\n\n    return cart_added\n\n\ndef body2(driver):\n    cart_block = driver.find_elements_by_xpath('//*[@title=\"View my shopping cart\"]')[0]\n\n    hover = ActionChains(driver).move_to_element(cart_block)\n    hover.perform()\n\n    boc = 'button_order_cart'\n    WebDriverWait(driver, 10).until(\n        EC.visibility_of_element_located((By.ID, boc)))\n\n    button_order_cart = driver.find_element(By.ID, boc)\n    button_order_cart.click()\n\n    total = 'total_price'\n    WebDriverWait(driver, 10).until(\n        EC.visibility_of_element_located((By.ID, total)))\n\n    price = driver.find_element(By.ID, total)\n    return price.text\n\n\n@sel_pool()\ndef test_url1(**kwargs):\n    driver = kwargs.pop('driver')\n    n = body(driver, \"dress\")\n    print('dress {}'.format(n))\n    #assert n == 7\n    assert n == 6, \"msg 1\" # wrong on purpose\n    m = body2(driver)\n    print('dress {}'.format(m))\n    #assert '$198.38' == m\n    assert '$197.38' == m, 'found {}'.format(m) # wrong on purpose\n\n\n@sel_pool()\ndef test_url2(**kwargs):\n    assert kwargs.pop('test') == 2\n    driver = kwargs.pop('driver')\n    n = body(driver, \"chiffon\")\n    print('chiffon {}'.format(n))\n    assert n == 2\n    m = body2(driver)\n    print('chiffon {}'.format(m))\n    assert '$48.90' == m, 'found {}'.format(m)\n```\n\u003c/p\u003e\u003c/details\u003e\n\n## Debugging\n\nWhen using input_queue.put(), to run a specific test that you need to debug, you simply need to only add only that test case to the queue.\n\nWhen using auto_fill_queue(), to run a specific test that you need to debug, use the prefix parameter to auto_fill_queue to match a method whose name you've altered.  \n## Built With\n\n* [selenium](https://pypi.org/project/selenium/) - Python bindings for Selenium\n* [Multiprocessing on Dill](https://pypi.org/project/multiprocessing_on_dill/) - A friendly fork of multiprocessing which uses dill instead of pickle\n* [attr](https://pypi.org/project/attr/) - Simple decorator to set attributes of target function or class in a DRY way.\n* [setuptools](https://pypi.org/project/setuptools/) - Easily download, build, install, upgrade, and uninstall Python packages\n\n\n## Authors\n\n* **Chris Mead** - *Initial work* - [TestLabAuto](https://github.com/testlabauto) - [Test Lab Automation](https://testlabauto.com/)\n\n\n## License\n\nThis project is licensed under the Apache License Version 2.0\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftestlabauto%2Flocal_selenium_pool","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftestlabauto%2Flocal_selenium_pool","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftestlabauto%2Flocal_selenium_pool/lists"}