{"id":16689219,"url":"https://github.com/sskorol/webdriver-supplier","last_synced_at":"2025-07-01T04:34:28.064Z","repository":{"id":24946438,"uuid":"102724741","full_name":"sskorol/webdriver-supplier","owner":"sskorol","description":"A small library which helps managing web browsers' lifecycle.","archived":false,"fork":false,"pushed_at":"2022-06-14T10:21:21.000Z","size":256,"stargazers_count":13,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-10T00:44:40.347Z","etag":null,"topics":["gradle","java","java-8","selenium","selenium-webdriver","testng","webdriver"],"latest_commit_sha":null,"homepage":"https://github.com/sskorol/webdriver-supplier","language":"Java","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/sskorol.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-09-07T10:37:01.000Z","updated_at":"2022-04-18T18:49:22.000Z","dependencies_parsed_at":"2022-08-24T11:20:34.772Z","dependency_job_id":null,"html_url":"https://github.com/sskorol/webdriver-supplier","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/sskorol/webdriver-supplier","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sskorol%2Fwebdriver-supplier","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sskorol%2Fwebdriver-supplier/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sskorol%2Fwebdriver-supplier/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sskorol%2Fwebdriver-supplier/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sskorol","download_url":"https://codeload.github.com/sskorol/webdriver-supplier/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sskorol%2Fwebdriver-supplier/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262898561,"owners_count":23381596,"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":["gradle","java","java-8","selenium","selenium-webdriver","testng","webdriver"],"created_at":"2024-10-12T15:47:32.477Z","updated_at":"2025-07-01T04:34:28.038Z","avatar_url":"https://github.com/sskorol.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# WebDriver Supplier \n\n[![Build Status](https://travis-ci.org/sskorol/webdriver-supplier.svg?branch=master)](https://travis-ci.org/sskorol/webdriver-supplier)\n[![codebeat badge](https://codebeat.co/badges/a0385906-b9a9-4287-b07f-70584e1e0702)](https://codebeat.co/projects/github-com-sskorol-webdriver-supplier-master)\n[![codecov](https://codecov.io/gh/sskorol/webdriver-supplier/branch/master/graph/badge.svg)](https://codecov.io/gh/sskorol/webdriver-supplier)\n[![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.github.sskorol/webdriver-supplier/badge.svg?style=flat)](https://maven-badges.herokuapp.com/maven-central/io.github.sskorol/webdriver-supplier)\n[![GitHub license](https://img.shields.io/badge/license-Apache%202-blue.svg)](https://goo.gl/9GLmMZ)\n[![Twitter](https://img.shields.io/twitter/url/https/github.com/sskorol/webdriver-supplier.svg?style=social)](https://twitter.com/intent/tweet?text=Check%20new%20WebDriver%20Supplier%20library:\u0026url=https://github.com/sskorol/webdriver-supplier)\n\nThis repository contains a web browser management tool.\n\n## Motivation\n\nYou know that WebDriver API helps to control browsers' behavior. However, Selenium is a pretty low level library, \nwhich can't protect users against common mistakes like NPE or race condition. \n\nBrowser management is not a trivial task, especially when tests must be scaled across different VMs or containers.\n\nIdeally, you should carefully think about architecture design to build a reliable module, \nwhich will automatically handle browsers' setup / cleanup activities, provide thread safety and reduce configuration overhead.\n\nThis library is intended to simplify and encapsulate all these processes from QA engineers, \nso that they could concentrate on more high level tasks.\n\n## Installation\n\n### Java 11 - Gradle\n\nAdd the following configuration into **build.gradle**:\n\n```groovy\nrepositories {\n    mavenCentral()\n}\n\nsourceCompatibility = JavaVersion.VERSION_11\ntargetCompatibility = JavaVersion.VERSION_11\n    \ndependencies {\n    compile(\n            'org.testng:testng:7.5',\n            'io.github.sskorol:webdriver-supplier:0.9.3'\n    )\n}\n    \ntest {\n    useTestNG() {\n        listeners \u003c\u003c 'io.github.sskorol.listeners.BeforeMethodListener'\n    }\n}\n```\n\n### Java 17 - Gradle\n\n```groovy\nrepositories {\n    mavenCentral()\n}\n\nsourceCompatibility = JavaVersion.VERSION_17\ntargetCompatibility = JavaVersion.VERSION_17\n    \ndependencies {\n    compile(\n            'org.testng:testng:7.6.0',\n            'io.github.sskorol:webdriver-supplier:1.1.3'\n    )\n}\n    \ntest {\n    useTestNG() {\n        listeners \u003c\u003c 'io.github.sskorol.listeners.BeforeMethodListener'\n    }\n}\n```\n\n### Java 11 - Maven\n\nAdd the following configuration into **pom.xml**:\n\n```xml\n\u003cdependencies\u003e\n    \u003cdependency\u003e\n        \u003cgroupId\u003eorg.testng\u003c/groupId\u003e\n        \u003cartifactId\u003etestng\u003c/artifactId\u003e\n        \u003cversion\u003e7.5\u003c/version\u003e\n    \u003c/dependency\u003e\n    \u003cdependency\u003e\n        \u003cgroupId\u003eio.github.sskorol\u003c/groupId\u003e\n        \u003cartifactId\u003ewebdriver-supplier\u003c/artifactId\u003e\n        \u003cversion\u003e0.9.3\u003c/version\u003e\n    \u003c/dependency\u003e\n\u003c/dependencies\u003e\n    \n\u003cbuild\u003e\n    \u003cplugins\u003e\n        \u003cplugin\u003e\n            \u003cgroupId\u003eorg.apache.maven.plugins\u003c/groupId\u003e\n            \u003cartifactId\u003emaven-compiler-plugin\u003c/artifactId\u003e\n            \u003cversion\u003e3.10.1\u003c/version\u003e\n            \u003cconfiguration\u003e\n                \u003csource\u003e11\u003c/source\u003e\n                \u003ctarget\u003e11\u003c/target\u003e\n            \u003c/configuration\u003e\n        \u003c/plugin\u003e\n        \u003cplugin\u003e\n            \u003cgroupId\u003eorg.apache.maven.plugins\u003c/groupId\u003e\n            \u003cartifactId\u003emaven-surefire-plugin\u003c/artifactId\u003e\n            \u003cversion\u003e3.0.0-M6\u003c/version\u003e\n            \u003cconfiguration\u003e\n                \u003cproperties\u003e\n                    \u003cproperty\u003e\n                        \u003cname\u003elistener\u003c/name\u003e\n                        \u003cvalue\u003eio.github.sskorol.listeners.BeforeMethodListener\u003c/value\u003e\n                    \u003c/property\u003e\n                \u003c/properties\u003e\n            \u003c/configuration\u003e\n        \u003c/plugin\u003e\n    \u003c/plugins\u003e\n\u003c/build\u003e\n```\n\n### Java 17 - Maven\n\n```xml\n\u003cdependencies\u003e\n    \u003cdependency\u003e\n        \u003cgroupId\u003eorg.testng\u003c/groupId\u003e\n        \u003cartifactId\u003etestng\u003c/artifactId\u003e\n        \u003cversion\u003e7.6.0\u003c/version\u003e\n    \u003c/dependency\u003e\n    \u003cdependency\u003e\n        \u003cgroupId\u003eio.github.sskorol\u003c/groupId\u003e\n        \u003cartifactId\u003ewebdriver-supplier\u003c/artifactId\u003e\n        \u003cversion\u003e1.1.3\u003c/version\u003e\n    \u003c/dependency\u003e\n\u003c/dependencies\u003e\n    \n\u003cbuild\u003e\n    \u003cplugins\u003e\n        \u003cplugin\u003e\n            \u003cgroupId\u003eorg.apache.maven.plugins\u003c/groupId\u003e\n            \u003cartifactId\u003emaven-compiler-plugin\u003c/artifactId\u003e\n            \u003cversion\u003e3.10.1\u003c/version\u003e\n            \u003cconfiguration\u003e\n                \u003csource\u003e17\u003c/source\u003e\n                \u003ctarget\u003e17\u003c/target\u003e\n            \u003c/configuration\u003e\n        \u003c/plugin\u003e\n        \u003cplugin\u003e\n            \u003cgroupId\u003eorg.apache.maven.plugins\u003c/groupId\u003e\n            \u003cartifactId\u003emaven-surefire-plugin\u003c/artifactId\u003e\n            \u003cversion\u003e3.0.0-M6\u003c/version\u003e\n            \u003cconfiguration\u003e\n                \u003cproperties\u003e\n                    \u003cproperty\u003e\n                        \u003cname\u003elistener\u003c/name\u003e\n                        \u003cvalue\u003eio.github.sskorol.listeners.BeforeMethodListener\u003c/value\u003e\n                    \u003c/property\u003e\n                \u003c/properties\u003e\n            \u003c/configuration\u003e\n        \u003c/plugin\u003e\n    \u003c/plugins\u003e\n\u003c/build\u003e\n```\n\n## Dependencies\n\n### TestNG\n\n**WebDriver Supplier** is driven by TestNG framework behind the scene. So basically you'll need to add a special \n**BeforeMethodListener** into build's configuration file, as described in installation section.\n\nThis listener will automatically raise a new web browser instance before a new test has started, \nand close it when test has finished.\n\n### Selenium\n\nAs web browsers are managed by WebDriver API, Selenium 4 is required for proper work. Note that library currently supports \nonly the following list of browsers (in both local and remote mode):\n\n - Chrome\n - Firefox\n - Internet Explorer\n - Edge\n\n### WebDriver Manager\n\nTo reduce an overhead with WebDrivers' binaries downloading and configuration, \n[webdrivermanager](https://github.com/bonigarcia/webdrivermanager) library was used. \nNote that it's required only for local tests execution.\n\n## Browser configuration\n\n**WebDriver Supplier** uses [SPI](https://docs.oracle.com/javase/tutorial/sound/SPI-intro.html) mechanism to provide \nbrowsers' implementations to the library core.\n\nBasically, you'll need to create a new class, which implements a special **Browser** interface.\n\n```java\npublic class Chrome implements Browser {\n        \n    public Name name() {\n        return Name.Chrome;\n    }\n}\n```\n\nBy default, only `name()` method should be overridden. You can pick one from the following enum:\n\n```java\nenum Name {\n    Chrome(\"chrome\"),\n    Firefox(\"firefox\"),\n    InternetExplorer(\"ie\"),\n    Edge(\"edge\"),\n    Remote(\"remote\");\n    //...\n}\n```\n\nNote that `Remote` constant is for internal usage only. If you want to run your tests remotely, you should override \n`isRemote()` method:\n\n```java\npublic boolean isRemote() {\n    return true;\n}\n```\n\nIf your hub's address differs from *localhost*, override the following:\n\n```java\npublic String url() {\n    return \"http://ip:port/wd/hub\";\n}\n```\n\nFinally, you can provide your own set of capabilities or options:\n\n```java\npublic Capabilities configuration(final XmlConfig config) {\n    final DesiredCapabilities caps = new DesiredCapabilities();\n    //...\n    return caps;\n}\n\npublic Capabilities configuration(final XmlConfig config) {\n    final ChromeOptions options = new ChromeOptions();\n    //...\n    return merge(config, options);\n}\n```\n\n```XmlConfig``` is a wrapper for TestNG suite. It gives an access to common browser configuration defined as parameters: \n**browserName**, **version** and **platform**. Besides that, you can also retrieve current test name. \n\nNote that you have to provide at least browser name on any of the following levels:\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003c!DOCTYPE suite SYSTEM \"https://testng.org/testng-1.0.dtd\" \u003e\n\u003csuite name=\"Suite name\"\u003e\n\t\u003c!-- Suite level parameters --\u003e\n\t\u003cparameter name=\"browserName\" value=\"chrome\"/\u003e\n\t\u003cparameter name=\"browserVersion\" value=\"1.1.0\"/\u003e\n\t\u003cparameter name=\"platformName\" value=\"MAC\"/\u003e\n\t\t\n\t\u003ctest name=\"Test block name\"\u003e\n\t\t\u003c!-- Test level parameters --\u003e\t\n\t\t\u003cparameter name=\"browserName\" value=\"firefox\"/\u003e\n\t\t\u003cparameter name=\"browserVersion\" value=\"1.1.1\"/\u003e\n\t\t\u003cparameter name=\"platformName\" value=\"LINUX\"/\u003e\n\t\t\n\t\t\u003cclasses\u003e\n\t\t\t\u003cclass name=\"path.to.your.TestClass\"\u003e\n\t\t\t\t\u003cmethods\u003e\n\t\t\t\t\t\u003c!-- Class level parameters --\u003e\n\t\t\t\t\t\u003cparameter name=\"browserName\" value=\"ie\"/\u003e\n\t\t\t\t\t\u003cparameter name=\"browserVersion\" value=\"1.1.2\"/\u003e\n\t\t\t\t\t\u003cparameter name=\"platformName\" value=\"WINDOWS\"/\u003e\n\t\t\t\t\t\n\t\t\t\t\t\u003cinclude name=\"methodName\"\u003e\n\t\t\t\t\t\t\u003c!-- Method level parameters --\u003e\n\t\t\t\t\t\t\u003cparameter name=\"browserName\" value=\"edge\"/\u003e\n\t\t\t\t\t\t\u003cparameter name=\"browserVersion\" value=\"1.1.3\"/\u003e\n\t\t\t\t\t\t\u003cparameter name=\"platformName\" value=\"WINDOWS\"/\u003e\n\t\t\t\t\t\u003c/include\u003e\n\t\t\t\t\u003c/methods\u003e\n\t\t\t\u003c/class\u003e\n\t\t\u003c/classes\u003e\n\t\u003c/test\u003e\n\u003c/suite\u003e\n```\n\nWhen all the levels are covered, only the lowest one is used. Configuration lookup goes in the following order: \nmethods, classes, tests, suites. If there was no **browserName** parameter found, corresponding test(-s) will be skipped.\n\nIndependently of browser's parameters location in xml, new instances will always be raised in **before method** \nconfiguration, and closed when test execution is finished. Assuming deep scaling support, it's not reasonable to open \nbrowsers in before class, test group or suite configuration.\n \nNote that in case of custom capabilities' usage, it's recommended to merge them with defaults:\n\n```java\npublic Capabilities configuration(final XmlConfig config) {\n    final DesiredCapabilities caps = new DesiredCapabilities();\n    //...\n    return merge(config, caps);\n}\n```\n\n`defaultConfiguration` method automatically handles browser-specific xml parameters, and creates corresponding capabilities. \nSo you don't need to set browserName / version / platform explicitly in code.\n\nWhen you finished with configuration staff, newly created browsers' implementation classes must be linked with a `Browser` SPI. \nAccording to official Oracle documentation, you should create **META-INF/services** folder within **resources** root, \nand put an SPI-named file **io.github.sskorol.core.Browser** there with a list of implementation classes:\n\n```text\nyour.full.path.to.Chrome\nyour.full.path.to.Firefox\nyour.full.path.to.Edge\nyour.full.path.to.Chrome\nyour.full.path.to.IE\n```  \n\nNote that it's not required to add all the implementations you have. But only specified items will be tracked by the \nlibrary internals.\n\n## Factory\n\n**WebDriver Supplier** has a preceded factory. So you don't need to care of browsers' initialization staff. \nNew instances will be automatically created depending on specified `Browser.Name` and `isRemote` flag in SPI \nimplementation classes.\n\nBut if you still want to manage WebDrivers manually, you can provide your own factory implementation. \nThis is handled by SPI mechanism as well. You just need to implement `WebDriverProvider` interface and put its reference \ninto **META-INF/services/io.github.sskorol.core.WebDriverProvider**. The same way it was described for `Browser` SPI.\n\nBy default you have to override the following methods:\n\n```java\nString label();\n    \nWebDriver createDriver(Browser browser, XmlConfig config);\n```\n\nWith `label` you can define a unique factory name, so that it could be identified by library internals. \n\n`createDriver` allows you getting actual info retrieved from `Browser` SPI implementation classes and TestNG xml.\n\n```java\npublic String label() {\n    return \"customFactory\";\n}\n    \npublic WebDriver createDriver(final Browser browser, final XmlConfig config) {\n    return Match(browser.name()).of(\n            Case($(Browser.Name.Firefox), () -\u003e new FirefoxDriver()),\n            Case($(Browser.Name.Chrome), () -\u003e new ChromeDriver())\n    );\n}\n```\n\n## WebDriver access\n\nNewly raised `WebDriver` instance can be retrieved via `getDriverMetaData` method call. Just add the following import \nto get full access to `Tuple2\u003cWebDriver, WebDriverWait\u003e`:\n\n```java\nimport static io.github.sskorol.listeners.BaseListener.getDriverMetaData;\n    \npublic abstract class BasePage {\n        \n    private final WebDriver driver;\n    private final WebDriverWait wait;\n        \n    public BasePage() {\n        final WebDriverContainer wdMeta = getDriverMetaData();\n        this.driver = wdMeta.getWebDriver();\n        this.wait = wdMeta.getWebDriverWait();\n    }\n}\n```\n\nBy default `WebDriverWait` is configured to wait for 10 sec until throwing a timeout exception. But you can override this \noption via **wd.wait.timeout** system property. It could be set either on configuration level in build.gradle / pom.xml, \nor by putting **webdriver.properties** with the same record into classpath.\n\n## Chrome DevTools Protocol\n\nSince 1.0.0 version `webdriver-supplier` introduces initial CDP support. Basically, your browser class should\nimplement `CDP` interface and override the following method to enable this feature:\n\n```java\npublic String cdpWebSocketUrl(final String sessionId) {\n    return format(\"ws://localhost:4444/devtools/%s/page\", sessionId);\n}\n```\n\nThe above example uses Selenoid to connect to the open websocket within browser's container.\n\nNext, you can access `ChromeDevToolsService` from within `WebDriverContainer`:\n\n```java\nfinal ChromeDevToolsService cdp = getDriverMetaData().getDevToolsService();\n```\n\n## Custom parameters\n\nIf you want to access custom parameters from `testng.xml` (e.g. as a feature toggling technique), you can use the following:\n\n```xml\n\u003cclasses\u003e\n    \u003cclass name=\"path.to.your.TestClass\"\u003e\n        \u003cparameter name=\"feature1\" value=\"value1\"/\u003e\n    \u003c/class\u003e\n\u003c/classes\u003e\n```\n\nThen you can access `XmlConfig` object with all scoped parameters from within WS container instance:\n```java\nfinal WebDriverContainer wdMeta = getDriverMetaData();\nfinal XmlConfig config = wdMeta.getConfig();\nOptional.ofNullable(config.getValue(\"feature1\"))\n    .ifPresent(System.out::println);\n```\n\n## SessionId access\n\nSometimes it might be useful to retrieve a current session id from `RemoteWebDriver` instance. For example,\n[Selenoid](http://aerokube.com/selenoid/latest/#_video_recording) uses session id as a default name for video recording.\n\n**webdriver-supplier** automatically injects `sessionId` as a custom TestNG attribute. It allows getting \ncorresponding access in e.g. `afterInvocation` event listener.\n\n```java\n@Slf4j\npublic class SessionListener implements IInvokedMethodListener {\n    //...\n            \n    @Override\n    public void afterInvocation(final IInvokedMethod method, final ITestResult testResult) {\n        if (method.isTestMethod()) {\n            log.info(\"Session ID = {}\", testResult.getAttribute(\"sessionId\"));\n        }\n    }\n}\n```\n\n## Taking screenshots\n\nScreenshots could be enabled either via boolean **wd.take.screenshot** system property or by putting **webdriver.properties** \nwith the same record into classpath.\n\nFor getting access to screenshots' content, it's required to implement the following SPI:\n\n```java\npublic class Screenshooter implements ScreenshotConsumer {\n        \n    @Override\n    public void handle(final byte[] screenshot, final ITestResult testResult) {\n        if (nonNull(screenshot) \u0026\u0026 testResult.getStatus() == FAILURE) {\n            // attach screenshot\n        }\n    }\n}\n\n```\n\nSimilar to `Browser` SPI, it should be added into **META-INF/services/io.github.sskorol.core.ScreenshotConsumer**.\n\n## WebDriver properties\n\n**webdriver.properties** file, put into classpath, allows defining or overriding the following settings:\n\n```text\nwd.wait.timeout = 10 (in sec)\nwd.screen.resolution = max (accepts WxH format, e.g. 1280x768)\nwd.take.screenshot = false\n```   \n\n## Full example\n\nTo establish connection with [Selenoid](http://aerokube.com/selenoid/latest) hub and Firefox node containers \nraised on localhost, you can use the following configuration:\n\n##### build.gradle\n\n```groovy\nrepositories {\n    mavenCentral()\n}\n\nsourceCompatibility = JavaVersion.VERSION_17\ntargetCompatibility = JavaVersion.VERSION_17\n    \ndependencies {\n    compile('org.testng:testng:7.6.0',\n            'io.github.sskorol:webdriver-supplier:1.1.1'\n    )\n}\n    \ntest {\n    useTestNG() {\n        listeners \u003c\u003c 'io.github.sskorol.listeners.BeforeMethodListener'\n        suites 'src/test/resources/smoke-suite.xml'\n    }\n}\n```\n\n##### Chrome.java\n\n```java\npublic class Chrome implements Browser, CDP {\n    \n    public Name name() {\n        return Name.Chrome;\n    }\n    \n    public boolean isRemote() {\n        return true;\n    }\n    \n    public Capabilities configuration(final XmlConfig config) {\n        final ChromeOptions options = new ChromeOptions();\n        options.setCapability(\"enableVNC\", true);\n        options.setCapability(\"enableVideo\", true);\n        options.setCapability(\"name\", config.getTestName());\n        options.setCapability(\"screenResolution\", \"1280x1024x24\");\n        return merge(config, options);\n    }\n\n    public String cdpWebSocketUrl(final String sessionId) {\n        return format(\"ws://localhost:4444/devtools/%s/page\", sessionId);\n    }\n}\n```\n\n##### io.github.sskorol.core.Browser\n\n```text\nfull.path.to.Chrome\n```\n\n##### smoke-suite.xml\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003c!DOCTYPE suite SYSTEM \"https://testng.org/testng-1.0.dtd\" \u003e\n\u003csuite name=\"Smoke suite\"\u003e\n\t\u003ctest name=\"Chrome group\"\u003e\n\t\t\u003cparameter name=\"browserName\" value=\"Chrome\"/\u003e\n\t\t\u003cparameter name=\"platformName\" value=\"LINUX\"/\u003e\n\t\t\u003cclasses\u003e\n\t\t\t\u003cclass name=\"path.to.your.testcases.SmokeTests\"/\u003e\n\t\t\u003c/classes\u003e\n\t\u003c/test\u003e\n\u003c/suite\u003e\n```\n\n##### BasePage.java\n\n```java\nimport static io.github.sskorol.listeners.BaseListener.getDriverMetaData;\n    \npublic abstract class BasePage {\n        \n    private final WebDriver driver;\n    private final WebDriverWait wait;\n    private final ChromeDevToolsService cdp;\n        \n    public BasePage() {\n        final WebDriverContainer wdMeta = getDriverMetaData();\n        this.driver = wdMeta.getWebDriver();\n        this.wait = wdMeta.getWebDriverWait();\n        this.cdp = wdMeta.getDevToolsService();\n    }\n    \n    protected void navigateTo(final String url) {\n        driver.get(url);\n    }    \n       \n    protected void click(final By locator) {\n        waitFor(locator, ExpectedConditions::elementToBeClickable).click();\n    }\n    \n    protected void type(final By locator, final CharSequence text) {\n        waitFor(locator, ExpectedConditions::visibilityOfElementLocated).sendKeys(text);\n    }\n        \n    private WebElement waitFor(final By locator, final Function\u003cBy, ExpectedCondition\u003cWebElement\u003e\u003e condition) {\n        return wait.until(condition.apply(locator));\n    }    \n}\n```\n\nThat's everything you need for a quick start. Enjoy it!\n\n## TBD\n\n- [ ] A separate GitHub project with usage examples.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsskorol%2Fwebdriver-supplier","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsskorol%2Fwebdriver-supplier","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsskorol%2Fwebdriver-supplier/lists"}