diff --git a/.gitignore b/.gitignore
index 65692b7..0959467 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,3 +17,4 @@ target/
 *.iml
 
 local.log
+reports
diff --git a/README.md b/README.md
index 7ef6726..fef1a68 100644
--- a/README.md
+++ b/README.md
@@ -10,9 +10,8 @@
 * Update `*.conf.js` files inside the `src/test/resources/conf/` directory to update desired capabilities.
 
 ## Running your tests
-* To run a single test, run `mvn compile exec:java -P single`
-* To run parallel tests, run `mvn compile exec:java -P parallel` 
-* To run local tests, run `mvn compile exec:java -P local`
+* To run tests, run `mvn test -P parallel` 
+* To run local tests, run `mvn test -P local`
 
 
 
diff --git a/pom.xml b/pom.xml
index 37a685e..76fe56d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -15,7 +15,8 @@
         <maven.compiler.source>1.8</maven.compiler.source>
         <maven.compiler.target>1.8</maven.compiler.target>
         <cucumber.version>6.9.1</cucumber.version>
-        <selenium-java.version>3.141.59</selenium-java.version>
+        <testng.version>7.4.0</testng.version>
+        <selenium-java.version>4.1.2</selenium-java.version>
         <browserstack-local-java.version>1.0.6</browserstack-local-java.version>
         <json-simple.version>1.1.1</json-simple.version>
         <slf4j.version>1.7.30</slf4j.version>
@@ -34,12 +35,24 @@
             <version>${slf4j.version}</version>
         </dependency>
 
+        <dependency>
+            <groupId>org.testng</groupId>
+            <artifactId>testng</artifactId>
+            <version>${testng.version}</version>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>io.cucumber</groupId>
             <artifactId>cucumber-java</artifactId>
             <version>${cucumber.version}</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>io.cucumber</groupId>
+            <artifactId>cucumber-testng</artifactId>
+            <version>${cucumber.version}</version>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>org.seleniumhq.selenium</groupId>
             <artifactId>selenium-java</artifactId>
@@ -81,37 +94,24 @@
     <profiles>
         <profile>
             <id>single</id>
-            <activation>
-                <activeByDefault>true</activeByDefault>
-            </activation>
             <build>
                 <plugins>
                     <plugin>
-                        <groupId>org.codehaus.mojo</groupId>
-                        <artifactId>exec-maven-plugin</artifactId>
-                        <version>3.0.0</version>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <version>3.0.0-M5</version>
                         <configuration>
-                            <classpathScope>test</classpathScope>
-                            <mainClass>com.browserstack.TestRunner</mainClass>
-                            <cleanupDaemonThreads>false</cleanupDaemonThreads>
-                            <systemProperties>
-                                <property>
-                                    <key>cucumber.publish.quiet</key>
-                                    <value>true</value>
-                                </property>
-                                <property>
-                                    <key>cucumber.plugin</key>
-                                    <value>html:target/cucumber-html-reports.html</value>
-                                </property>
-                                <property>
-                                    <key>caps</key>
-                                    <value>src/test/resources/conf/single.conf.json</value>
-                                </property>
-                                <property>
-                                    <key>features</key>
-                                    <value>src/test/resources/features/test</value>
-                                </property>
-                            </systemProperties>
+                            <suiteXmlFiles>
+                                <suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile>
+                            </suiteXmlFiles>
+                            <argLine>
+                                -Ddataproviderthreadcount=1
+                            </argLine>
+                            <systemPropertyVariables>
+                                <caps>src/test/resources/conf/single.conf.json</caps>
+                                <cucumber.publish.quiet>true</cucumber.publish.quiet>
+                                <cucumber.features>src/test/resources/features/test</cucumber.features>
+                            </systemPropertyVariables>
                         </configuration>
                     </plugin>
                 </plugins>
@@ -119,38 +119,33 @@
         </profile>
         <profile>
             <id>parallel</id>
+            <activation>
+                <activeByDefault>true</activeByDefault>
+            </activation>
             <build>
                 <plugins>
                     <plugin>
-                        <groupId>org.codehaus.mojo</groupId>
-                        <artifactId>exec-maven-plugin</artifactId>
-                        <version>3.0.0</version>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <version>3.0.0-M5</version>
                         <configuration>
-                            <classpathScope>test</classpathScope>
-                            <mainClass>com.browserstack.TestRunner</mainClass>
-                            <cleanupDaemonThreads>false</cleanupDaemonThreads>
-                            <systemProperties>
-                                <property>
-                                    <key>cucumber.publish.quiet</key>
-                                    <value>true</value>
-                                </property>
+                            <suiteXmlFiles>
+                                <suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile>
+                            </suiteXmlFiles>
+                            <argLine>
+                                -Ddataproviderthreadcount=4
+                            </argLine>
+                            <systemPropertyVariables>
+                                <caps>src/test/resources/conf/parallel.conf.json</caps>
+                                <cucumber.publish.quiet>true</cucumber.publish.quiet>
+                                <cucumber.features>src/test/resources/features/test</cucumber.features>
+                            </systemPropertyVariables>
+                            <properties>
                                 <property>
-                                    <key>cucumber.plugin</key>
-                                    <value>html:target/cucumber-html-reports.html</value>
+                                    <name>parallel</name>
+                                    <value>methods</value>
                                 </property>
-                                <property>
-                                    <key>caps</key>
-                                    <value>src/test/resources/conf/parallel.conf.json</value>
-                                </property>
-                                <property>
-                                    <key>parallel-count</key>
-                                    <value>5</value>
-                                </property>
-                                <property>
-                                    <key>features</key>
-                                    <value>src/test/resources/features/test</value>
-                                </property>
-                            </systemProperties>
+                            </properties>
                         </configuration>
                     </plugin>
                 </plugins>
@@ -161,31 +156,21 @@
             <build>
                 <plugins>
                     <plugin>
-                        <groupId>org.codehaus.mojo</groupId>
-                        <artifactId>exec-maven-plugin</artifactId>
-                        <version>3.0.0</version>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <version>3.0.0-M5</version>
                         <configuration>
-                            <classpathScope>test</classpathScope>
-                            <mainClass>com.browserstack.TestRunner</mainClass>
-                            <cleanupDaemonThreads>false</cleanupDaemonThreads>
-                            <systemProperties>
-                                <property>
-                                    <key>cucumber.publish.quiet</key>
-                                    <value>true</value>
-                                </property>
-                                <property>
-                                    <key>cucumber.plugin</key>
-                                    <value>html:target/cucumber-html-reports.html</value>
-                                </property>
-                                <property>
-                                    <key>caps</key>
-                                    <value>src/test/resources/conf/local.conf.json</value>
-                                </property>
-                                <property>
-                                    <key>features</key>
-                                    <value>src/test/resources/features/localtest</value>
-                                </property>
-                            </systemProperties>
+                            <suiteXmlFiles>
+                                <suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile>
+                            </suiteXmlFiles>
+                            <argLine>
+                                -Ddataproviderthreadcount=1
+                            </argLine>
+                            <systemPropertyVariables>
+                                <caps>src/test/resources/conf/local.conf.json</caps>
+                                <cucumber.publish.quiet>true</cucumber.publish.quiet>
+                                <cucumber.features>src/test/resources/features/localtest</cucumber.features>
+                            </systemPropertyVariables>
                         </configuration>
                     </plugin>
                 </plugins>
diff --git a/src/test/java/com/browserstack/RunWebDriverCucumberTests.java b/src/test/java/com/browserstack/RunWebDriverCucumberTests.java
new file mode 100644
index 0000000..7ff3935
--- /dev/null
+++ b/src/test/java/com/browserstack/RunWebDriverCucumberTests.java
@@ -0,0 +1,83 @@
+package com.browserstack;
+
+import java.util.Iterator;
+
+import com.browserstack.local.Local;
+import com.browserstack.util.Utility;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import com.browserstack.webdriver.LazyInitWebDriverIterator;
+import com.browserstack.webdriver.ManagedWebDriver;
+import io.cucumber.testng.CucumberOptions;
+import io.cucumber.testng.FeatureWrapper;
+import io.cucumber.testng.PickleWrapper;
+import io.cucumber.testng.TestNGCucumberRunner;
+
+@CucumberOptions(
+        glue = "com.browserstack.stepdefs",
+        plugin = {
+                "pretty",
+                "html:reports/tests/cucumber/html",
+                "timeline:reports/tests/cucumber/timeline",
+                "junit:reports/tests/cucumber/junit/cucumber.xml",
+                "testng:reports/tests/cucumber/testng/cucumber.xml",
+                "json:reports/tests/cucumber/json/cucumber.json"
+        }
+)
+public class RunWebDriverCucumberTests {
+
+    private TestNGCucumberRunner testNGCucumberRunner;
+    private static Local local;
+    private static final ThreadLocal<ManagedWebDriver> threadLocalWebDriver = new ThreadLocal<>();
+
+    @BeforeClass(alwaysRun = true)
+    public void setUpClass() {
+        testNGCucumberRunner = new TestNGCucumberRunner(this.getClass());
+    }
+
+    private synchronized static void setThreadLocalWebDriver(ManagedWebDriver managedWebDriver) {
+        threadLocalWebDriver.set(managedWebDriver);
+        if(Utility.isLocal(managedWebDriver) && local==null){
+            local = new Local();
+            Utility.startLocal(local, managedWebDriver);
+        }
+      
+    }
+
+    public synchronized static ManagedWebDriver getManagedWebDriver() {
+        return threadLocalWebDriver.get();
+    }
+
+    @Test(groups = "cucumber", description = "Runs Cucumber Feature", dataProvider = "scenarios")
+    public void feature(PickleWrapper pickleWrapper, FeatureWrapper featureWrapper, ManagedWebDriver managedWebDriver) {
+        managedWebDriver.setTestName(pickleWrapper.getPickle().getName());
+        setThreadLocalWebDriver(managedWebDriver);
+        testNGCucumberRunner.runScenario(pickleWrapper.getPickle());
+    }
+
+    @DataProvider(name = "scenarios", parallel = true)
+    public Iterator<Object[]> scenarios() {
+        Object[][] scenarios = testNGCucumberRunner.provideScenarios();
+        //Get Iterator of Object arrays consisting PickleWrapper, FeatureWrapper and ManagedWebDriver
+        return new LazyInitWebDriverIterator(scenarios);
+    }
+
+    @AfterClass(alwaysRun = true)
+    public void tearDownClass() {
+        if(local != null){
+            try {
+                local.stop();
+            } catch (Exception e) {
+                throw new Error("Unable to stop BrowserStack Local.");
+            }
+        }
+        if (testNGCucumberRunner == null) {
+            return;
+        }
+        testNGCucumberRunner.finish();
+    }
+
+}
diff --git a/src/test/java/com/browserstack/TestRunner.java b/src/test/java/com/browserstack/TestRunner.java
deleted file mode 100644
index 1993e98..0000000
--- a/src/test/java/com/browserstack/TestRunner.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package com.browserstack;
-
-import com.browserstack.util.Utility;
-import io.cucumber.core.cli.Main;
-import org.apache.commons.lang3.StringUtils;
-import org.json.simple.JSONArray;
-import org.json.simple.JSONObject;
-import org.json.simple.parser.JSONParser;
-import org.json.simple.parser.ParseException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.FileReader;
-import java.io.IOException;
-import java.util.Map;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-public class TestRunner {
-    public static ThreadLocal<JSONObject> threadLocalValue = new ThreadLocal<>();
-
-    public static void main(String[] args) throws IOException, ParseException {
-        JSONObject testConfig;
-        int threadCount = 1;
-        JSONParser parser = new JSONParser();
-        if (StringUtils.isNoneEmpty(System.getProperty("parallel-count")) && StringUtils.isNumeric(System.getProperty("parallel-count"))) {
-            threadCount = Integer.parseInt(System.getProperty("parallel-count"));
-        }
-        if (System.getProperty("caps") != null) {
-            testConfig = (JSONObject) parser.parse(new FileReader(System.getProperty("caps")));
-        } else {
-            testConfig = (JSONObject) parser.parse(new FileReader("src/test/resources/conf/single.conf.json"));
-        }
-        JSONArray environments = (JSONArray) testConfig.get("environments");
-        ExecutorService pool = Executors.newFixedThreadPool(threadCount);
-        for (Object obj : environments) {
-            JSONObject singleConfig = Utility.getCombinedCapability((Map<String, String>) obj, testConfig);
-            Runnable task = new Task(singleConfig, threadLocalValue, System.getProperty("features"), testConfig.get("server").toString());
-            pool.execute(task);
-        }
-        pool.shutdown();
-    }
-
-}
-
-class Task implements Runnable {
-    private JSONObject singleConfig;
-    private ThreadLocal<JSONObject> threadLocalValue;
-    private String features;
-    private String server;
-
-    public static Logger log = LoggerFactory.getLogger(TestRunner.class);
-
-    public Task(JSONObject singleConfig, ThreadLocal<JSONObject> threadLocalValue, String features, String server) {
-        this.singleConfig = singleConfig;
-        this.threadLocalValue = threadLocalValue;
-        this.features = features;
-        this.server = server;
-    }
-
-    public void run() {
-        System.setProperty("server", server);
-        threadLocalValue.set(singleConfig);
-        try {
-            String[] argv = new String[]{"-g", "", features };
-            ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
-            Main.run(argv, contextClassLoader);
-        } catch (Exception e) {
-            log.error("Error with parallel test", e);
-        } finally {
-            threadLocalValue.remove();
-        }
-    }
-}
diff --git a/src/test/java/com/browserstack/pageobjects/HomePage.java b/src/test/java/com/browserstack/pageobjects/HomePage.java
new file mode 100644
index 0000000..33dfd00
--- /dev/null
+++ b/src/test/java/com/browserstack/pageobjects/HomePage.java
@@ -0,0 +1,52 @@
+package com.browserstack.pageobjects;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+import java.time.Duration;
+
+public class HomePage {
+    private WebDriver webDriver;
+
+    private String selectedProductName;
+
+    public HomePage(WebDriver webDriver) {
+        this.webDriver = webDriver;
+        this.selectedProductName = "";
+    }
+
+    private By firstProductName = By.xpath("//*[@id=\"1\"]/p");
+
+    private By firstProductAddToCartButton = By.xpath("//*[@id=\"1\"]/div[4]");
+
+    private By cartPane = By.cssSelector(".float-cart__content");
+
+    private By productCartText = By.xpath("//*[@id=\"__next\"]/div/div/div[2]/div[2]/div[2]/div/div[3]/p[1]");
+
+    public void selectFirstProductName() {
+        String firstProduct = webDriver.findElement(firstProductName).getText();
+        setSelectedProductName(firstProduct);
+    }
+
+    public void clickAddToCartButton() {
+        webDriver.findElement(firstProductAddToCartButton).click();
+    }
+
+    public void waitForCartToOpen() {
+        new WebDriverWait(webDriver, Duration.ofSeconds(30)).until(ExpectedConditions.visibilityOfAllElementsLocatedBy(cartPane));
+    }
+
+    public String getProductCartText() {
+        return webDriver.findElement(productCartText).getText();
+    }
+
+    public void setSelectedProductName(String selectedProductName) {
+        this.selectedProductName = selectedProductName;
+    }
+
+    public String getSelectedProductName() {
+        return selectedProductName;
+    }
+}
diff --git a/src/test/java/com/browserstack/pageobjects/SearchPage.java b/src/test/java/com/browserstack/pageobjects/SearchPage.java
deleted file mode 100644
index e7cb592..0000000
--- a/src/test/java/com/browserstack/pageobjects/SearchPage.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.browserstack.pageobjects;
-
-import org.openqa.selenium.By;
-import org.openqa.selenium.WebDriver;
-
-public class SearchPage {
-    private WebDriver webDriver;
-
-    public SearchPage(WebDriver webDriver) {
-        this.webDriver = webDriver;
-    }
-
-    private By searchTermField = By.name("q");
-
-    public void enterSearchTerm(String searchTerm) {
-        webDriver.findElement(searchTermField).sendKeys(searchTerm);
-    }
-
-    public void submitSearch() {
-        webDriver.findElement(searchTermField).submit();
-    }
-
-}
diff --git a/src/test/java/com/browserstack/stepdefs/SearchSteps.java b/src/test/java/com/browserstack/stepdefs/SearchSteps.java
deleted file mode 100644
index acce60e..0000000
--- a/src/test/java/com/browserstack/stepdefs/SearchSteps.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package com.browserstack.stepdefs;
-
-import com.browserstack.TestRunner;
-import com.browserstack.local.Local;
-import com.browserstack.pageobjects.SearchPage;
-import com.browserstack.util.Utility;
-import io.cucumber.java.After;
-import io.cucumber.java.Before;
-import io.cucumber.java.Scenario;
-import io.cucumber.java.en.Given;
-import io.cucumber.java.en.Then;
-import io.cucumber.java.en.When;
-import org.json.simple.JSONObject;
-import org.openqa.selenium.WebDriver;
-import org.openqa.selenium.remote.DesiredCapabilities;
-import org.openqa.selenium.remote.RemoteWebDriver;
-
-import java.net.URL;
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-public class SearchSteps {
-    private WebDriver driver;
-    private SearchPage searchPage;
-    private Local l;
-
-    @Before
-    public void setUp(Scenario scenario) throws Exception {
-        JSONObject capability = TestRunner.threadLocalValue.get();
-        String URL = String.format("https://%s/wd/hub",System.getProperty("server"));
-
-        DesiredCapabilities caps = new DesiredCapabilities(capability);
-        caps.setCapability("name", scenario.getName());
-        if (caps.getCapability("browserstack.local")!=null && caps.getCapability("browserstack.local").toString().equals("true")) {
-            l = new Local();
-            Map<String, String> options = new HashMap<String, String>();
-            options.put("key", caps.getCapability("browserstack.key").toString());
-            l.start(options);
-        }
-
-        driver = new RemoteWebDriver(new URL(URL), caps);
-        searchPage = new SearchPage(driver);
-    }
-
-    @Given("^I am on the website '(.+)'$")
-    public void I_am_on_the_website(String url) throws Throwable {
-        driver.get(url);
-        Thread.sleep(2000);
-    }
-
-    @When("^I submit the search term '(.+)'$")
-    public void I_submit_the_search_term(String searchTerm) throws Throwable {
-        searchPage.enterSearchTerm(searchTerm);
-        searchPage.submitSearch();
-        Thread.sleep(2000);
-    }
-
-    @Then("the page title should be '(.+)'$")
-    public void I_should_see_pagetitle(String expectedTitle) throws Throwable {
-        assertEquals(expectedTitle, driver.getTitle());
-    }
-
-    @Then("the page should contain '(.+)'$")
-    public void page_should_contain(String expectedTitle) throws Throwable {
-        assertTrue(driver.getPageSource().contains(expectedTitle));
-    }
-
-    @After
-    public void teardown(Scenario scenario) throws Exception {
-        if (scenario.isFailed()) {
-            Utility.setSessionStatus(driver, "failed", String.format("%s failed.", scenario.getName()));
-        } else {
-            Utility.setSessionStatus(driver, "passed", String.format("%s passed.", scenario.getName()));
-        }
-        Thread.sleep(2000);
-        driver.quit();
-        if (l != null) l.stop();
-    }
-}
\ No newline at end of file
diff --git a/src/test/java/com/browserstack/stepdefs/StackDemoSteps.java b/src/test/java/com/browserstack/stepdefs/StackDemoSteps.java
new file mode 100644
index 0000000..27b2df5
--- /dev/null
+++ b/src/test/java/com/browserstack/stepdefs/StackDemoSteps.java
@@ -0,0 +1,61 @@
+package com.browserstack.stepdefs;
+
+import com.browserstack.RunWebDriverCucumberTests;
+import com.browserstack.pageobjects.HomePage;
+import com.browserstack.util.Utility;
+import io.cucumber.java.After;
+import io.cucumber.java.Before;
+import io.cucumber.java.Scenario;
+import io.cucumber.java.en.Given;
+import io.cucumber.java.en.Then;
+import io.cucumber.java.en.When;
+import org.openqa.selenium.WebDriver;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class StackDemoSteps {
+    private WebDriver driver;
+    private HomePage homePage;
+
+    @Before
+    public void setUp() {
+        driver = RunWebDriverCucumberTests.getManagedWebDriver().getWebDriver();
+        homePage = new HomePage(driver);
+    }
+
+    @Given("^I am on the website '(.+)'$")
+    public void I_am_on_the_website(String url) throws Throwable {
+        driver.get(url);
+        Thread.sleep(2000);
+    }
+
+    @When("^I select a product and click on 'Add to cart' button")
+    public void I_select_a_product_and_add_to_cart() throws Throwable {
+        homePage.selectFirstProductName();
+        homePage.clickAddToCartButton();
+        Thread.sleep(2000);
+    }
+
+    @Then("the product should be added to cart")
+    public void product_should_be_added_to_cart() {
+        homePage.waitForCartToOpen();
+        assertEquals(homePage.getSelectedProductName(), homePage.getProductCartText());
+    }
+
+    @Then("the page should contain '(.+)'$")
+    public void page_should_contain(String expectedTitle) {
+        assertTrue(driver.getPageSource().contains(expectedTitle));
+    }
+
+    @After
+    public void teardown(Scenario scenario) throws Exception {
+        if (scenario.isFailed()) {
+            Utility.setSessionStatus(driver, "failed", String.format("%s failed.", scenario.getName()));
+        } else {
+            Utility.setSessionStatus(driver, "passed", String.format("%s passed.", scenario.getName()));
+        }
+        Thread.sleep(2000);
+        driver.quit();
+    }
+}
diff --git a/src/test/java/com/browserstack/util/Utility.java b/src/test/java/com/browserstack/util/Utility.java
index 1f30bd1..6ff23d0 100644
--- a/src/test/java/com/browserstack/util/Utility.java
+++ b/src/test/java/com/browserstack/util/Utility.java
@@ -1,9 +1,14 @@
 package com.browserstack.util;
 
+import com.browserstack.local.Local;
+import com.browserstack.webdriver.ManagedWebDriver;
 import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
 import org.openqa.selenium.JavascriptExecutor;
 import org.openqa.selenium.WebDriver;
 
+import java.io.FileReader;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
 
@@ -15,13 +20,13 @@ public static JSONObject getCombinedCapability(Map<String, String> envCapabiliti
         Iterator it = envCapabilities.entrySet().iterator();
         while (it.hasNext()) {
             Map.Entry pair = (Map.Entry) it.next();
-            capabilities.put(pair.getKey().toString(), pair.getValue().toString());
+            capabilities.put(pair.getKey().toString(), pair.getValue());
         }
         it = commonCapabilities.entrySet().iterator();
         while (it.hasNext()) {
             Map.Entry pair = (Map.Entry) it.next();
             if (capabilities.get(pair.getKey().toString()) == null) {
-                capabilities.put(pair.getKey().toString(), pair.getValue().toString());
+                capabilities.put(pair.getKey().toString(), pair.getValue());
             }
         }
         String username = System.getenv("BROWSERSTACK_USERNAME");
@@ -33,8 +38,13 @@ public static JSONObject getCombinedCapability(Map<String, String> envCapabiliti
         if(accessKey == null) {
             accessKey = (String) config.get("key");
         }
-        capabilities.put("browserstack.user", username);
-        capabilities.put("browserstack.key", accessKey);
+        JSONObject bstackOptions = (JSONObject) capabilities.get("bstack:options");
+        if(bstackOptions == null)
+            bstackOptions = new JSONObject();
+        bstackOptions.put("userName", username);
+        bstackOptions.put("accessKey", accessKey);
+        bstackOptions.put("source", "cucumber-java:sample-selenium-4:v1.1");
+        capabilities.put("bstack:options", bstackOptions);
         return capabilities;
     }
 
@@ -42,4 +52,29 @@ public static void setSessionStatus(WebDriver webDriver, String status, String r
         JavascriptExecutor jse = (JavascriptExecutor) webDriver;
         jse.executeScript(String.format("browserstack_executor: {\"action\": \"setSessionStatus\", \"arguments\": {\"status\": \"%s\", \"reason\": \"%s\"}}", status, reason));
     }
+
+    public static boolean isLocal(ManagedWebDriver managedWebDriver) {
+        JSONObject platform = managedWebDriver.getPlatform();
+        Map<String, Object> bstackOptions = (Map<String, Object>) platform.get("bstack:options");
+        return bstackOptions!=null && bstackOptions.get("local")!=null && bstackOptions.get("local").toString().equals("true");
+    }
+
+    public static void startLocal(Local local, ManagedWebDriver managedWebDriver) {
+        JSONParser parser = new JSONParser();
+        Map<String, String> options = new HashMap<>();
+        JSONObject platform = managedWebDriver.getPlatform();
+        Map<String, Object> bstackOptions = (Map<String, Object>) platform.get("bstack:options");
+        options.put("key", bstackOptions.get("accessKey").toString());
+        String capabilitiesConfigFile = System.getProperty("caps", "src/test/resources/conf/local.conf.json");
+        try {
+            JSONObject testConfig = (JSONObject) parser.parse(new FileReader(capabilitiesConfigFile));
+            if(testConfig.containsKey("localOptions")) {
+                JSONObject localOptions = (JSONObject) testConfig.get("localOptions");
+                options.forEach(localOptions::putIfAbsent);
+            }
+            local.start(options);
+        } catch (Exception e) {
+            throw new Error("Unable to start BrowserStack Local.");
+        }
+    }
 }
diff --git a/src/test/java/com/browserstack/webdriver/LazyInitWebDriverIterator.java b/src/test/java/com/browserstack/webdriver/LazyInitWebDriverIterator.java
new file mode 100644
index 0000000..f7ead4a
--- /dev/null
+++ b/src/test/java/com/browserstack/webdriver/LazyInitWebDriverIterator.java
@@ -0,0 +1,73 @@
+package com.browserstack.webdriver;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.stream.Collectors;
+
+import org.json.simple.JSONObject;
+
+public class LazyInitWebDriverIterator implements Iterator<Object[]> {
+    private final String testMethodName;
+    private final List<JSONObject> platforms;
+    private final List<Object[]> testParams;
+    private int paramIndex = 0;
+
+    public LazyInitWebDriverIterator(Object[][] testParams) {
+        this.testMethodName = "";
+        this.platforms = WebDriverFactory.getInstance().getPlatforms();
+        List<Object[]> testParamsList = new ArrayList();
+        if (testParams != null) {
+            testParamsList = (List)Arrays.stream(testParams).collect(Collectors.toList());
+        }
+
+        //Create list of combinations of Scenarios and Platforms
+        this.testParams = this.populateTestParams((List)testParamsList);
+    }
+
+    private List<Object[]> populateTestParams(List<Object[]> testParams) {
+        int index = 0;
+        ArrayList tempTestParams = new ArrayList();
+
+        do {
+            Object[] testParam = (Object[])testParams.get(index);
+            if (testParam == null) {
+                testParam = new Object[0];
+            }
+
+            Iterator platformsIterator = this.platforms.iterator();
+
+            while(platformsIterator.hasNext()) {
+                JSONObject platform = (JSONObject)platformsIterator.next();
+                Object[] paramsWithPlatform = Arrays.copyOf(testParam, testParam.length + 1);
+                paramsWithPlatform[paramsWithPlatform.length - 1] = platform;
+                tempTestParams.add(paramsWithPlatform);
+            }
+
+            ++index;
+        } while(index < testParams.size());
+
+        return tempTestParams;
+    }
+
+    public boolean hasNext() {
+        return this.paramIndex < this.testParams.size();
+    }
+
+    public Object[] next() {
+        if (this.paramIndex >= this.testParams.size()) {
+            throw new NoSuchElementException("No More Platforms configured to create WebDriver for.");
+        } else {
+            Object[] methodTestParams = (Object[])this.testParams.get(this.paramIndex++);
+            if (methodTestParams[methodTestParams.length - 1] instanceof JSONObject) {
+                JSONObject platform = (JSONObject)methodTestParams[methodTestParams.length - 1];
+                ManagedWebDriver managedWebDriver = new ManagedWebDriver(this.testMethodName, platform);
+                methodTestParams[methodTestParams.length - 1] = managedWebDriver;
+            }
+            //return an Object array consisting PickleWrapper, FeatureWrapper and ManagedWebDriver
+            return methodTestParams;
+        }
+    }
+}
diff --git a/src/test/java/com/browserstack/webdriver/ManagedWebDriver.java b/src/test/java/com/browserstack/webdriver/ManagedWebDriver.java
new file mode 100644
index 0000000..51d09e2
--- /dev/null
+++ b/src/test/java/com/browserstack/webdriver/ManagedWebDriver.java
@@ -0,0 +1,33 @@
+package com.browserstack.webdriver;
+
+import org.json.simple.JSONObject;
+import org.openqa.selenium.WebDriver;
+
+public class ManagedWebDriver {
+    private String testName;
+    private final WebDriverFactory webDriverFactory;
+    private final JSONObject platform;
+    private WebDriver webDriver;
+
+    public ManagedWebDriver(String testMethodName, JSONObject platform) {
+        this.testName = testMethodName;
+        this.platform = platform;
+        this.webDriverFactory = WebDriverFactory.getInstance();
+    }
+
+    public void setTestName(String testName) {
+        this.testName = testName;
+    }
+
+    public JSONObject getPlatform() {
+        return this.platform;
+    }
+
+    public WebDriver getWebDriver() {
+        if (this.webDriver == null) {
+            this.webDriver = this.webDriverFactory.createWebDriverForPlatform(this.platform, this.testName);
+        }
+
+        return this.webDriver;
+    }
+}
diff --git a/src/test/java/com/browserstack/webdriver/WebDriverFactory.java b/src/test/java/com/browserstack/webdriver/WebDriverFactory.java
new file mode 100644
index 0000000..24314c1
--- /dev/null
+++ b/src/test/java/com/browserstack/webdriver/WebDriverFactory.java
@@ -0,0 +1,72 @@
+package com.browserstack.webdriver;
+
+import com.browserstack.util.Utility;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.remote.DesiredCapabilities;
+import org.openqa.selenium.remote.RemoteWebDriver;
+
+import java.io.FileReader;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class WebDriverFactory {
+
+    private static volatile WebDriverFactory instance;
+    private final JSONObject testConfig = this.parseWebDriverConfig();
+
+    private WebDriverFactory() {
+    }
+
+    public static WebDriverFactory getInstance() {
+        if (instance == null) {
+            synchronized(WebDriverFactory.class) {
+                if (instance == null) {
+                    instance = new WebDriverFactory();
+                }
+            }
+        }
+
+        return instance;
+    }
+
+    private JSONObject parseWebDriverConfig() {
+        JSONParser parser = new JSONParser();
+        String capabilitiesConfigFile = System.getProperty("caps", "src/test/resources/conf/single.conf.json");
+        try {
+            JSONObject testConfig = (JSONObject) parser.parse(new FileReader(capabilitiesConfigFile));
+            return testConfig;
+        } catch (IOException | ParseException var6) {
+            throw new Error("Unable to parse capabilities file " + capabilitiesConfigFile, var6);
+        }
+    }
+
+    public List<JSONObject> getPlatforms() {
+        JSONArray environments = (JSONArray) testConfig.get("environments");
+        List<JSONObject> platforms = new ArrayList<>();
+        for (Object obj : environments) {
+            JSONObject singleConfig = Utility.getCombinedCapability((Map<String, String>) obj, testConfig);
+            platforms.add(singleConfig);
+        }
+        return platforms;
+    }
+
+    public WebDriver createWebDriverForPlatform(JSONObject platform, String testName) {
+        try {
+            String URL = String.format("https://%s/wd/hub", testConfig.get("server"));
+            DesiredCapabilities caps = new DesiredCapabilities(platform);
+            caps.setCapability("name", testName);
+            return new RemoteWebDriver(new URL(URL), caps);
+        } catch (MalformedURLException var4) {
+            throw new Error("Unable to create WebDriver", var4);
+        }
+    }
+
+}
diff --git a/src/test/resources/conf/local.conf.json b/src/test/resources/conf/local.conf.json
index 306fa86..c6ad5b5 100644
--- a/src/test/resources/conf/local.conf.json
+++ b/src/test/resources/conf/local.conf.json
@@ -4,12 +4,18 @@
   "key": "BROWSERSTACK_ACCESS_KEY",
 
   "capabilities": {
-    "build": "cucumber-java-browserstack",
-    "browserstack.debug": true,
-    "browserstack.local": true
+    "bstack:options": {
+      "buildName": "cucumber-java-browserstack",
+      "local": "true",
+      "debug": "true"
+    }
   },
 
   "environments": [{
-    "browser": "chrome"
-  }]
+    "browserName": "chrome"
+  }],
+
+  "localOptions": {
+    "forceLocal": true
+  }
 }
diff --git a/src/test/resources/conf/parallel.conf.json b/src/test/resources/conf/parallel.conf.json
index 67d5177..6590da0 100644
--- a/src/test/resources/conf/parallel.conf.json
+++ b/src/test/resources/conf/parallel.conf.json
@@ -4,22 +4,21 @@
   "key": "BROWSERSTACK_ACCESS_KEY",
 
   "capabilities": {
-    "build": "cucumber-java-browserstack",
-    "browserstack.debug": true
+    "bstack:options": {
+      "buildName": "cucumber-java-browserstack",
+      "debug": "true"
+    }
   },
 
   "environments": [
     {
-      "browser": "chrome"
-    },
-    {
-      "browser": "firefox"
+      "browserName": "chrome"
     },
     {
-      "browser": "safari"
+      "browserName": "firefox"
     },
     {
-      "browser": "Internet Explorer"
+      "browserName": "safari"
     }
   ]
 }
diff --git a/src/test/resources/conf/single.conf.json b/src/test/resources/conf/single.conf.json
index 0f2dc7a..ee140d3 100644
--- a/src/test/resources/conf/single.conf.json
+++ b/src/test/resources/conf/single.conf.json
@@ -4,11 +4,13 @@
   "key": "BROWSERSTACK_ACCESS_KEY",
 
   "capabilities": {
-    "build": "cucumber-java-browserstack",
-    "browserstack.debug": true
+    "bstack:options": {
+      "buildName": "cucumber-java-browserstack",
+      "debug": "true"
+    }
   },
 
   "environments": [{
-    "browser": "chrome"
+    "browserName": "chrome"
   }]
 }
diff --git a/src/test/resources/features/localtest/Local.feature b/src/test/resources/features/localtest/Local.feature
index 8d1601f..1e3d812 100644
--- a/src/test/resources/features/localtest/Local.feature
+++ b/src/test/resources/features/localtest/Local.feature
@@ -1,5 +1,5 @@
 Feature: Verify Local test
 
-  Scenario: Navigate to Local check page
+  Scenario: BStack Local Test - Navigate to Local check page
     Given I am on the website 'http://bs-local.com:45691/check'
-    Then the page should contain 'Up and running'
\ No newline at end of file
+    Then the page should contain 'Up and running'
diff --git a/src/test/resources/features/test/Search.feature b/src/test/resources/features/test/Search.feature
deleted file mode 100644
index 48e0bac..0000000
--- a/src/test/resources/features/test/Search.feature
+++ /dev/null
@@ -1,6 +0,0 @@
-Feature: Automatically correct mistyped search terms
-
-  Scenario: Enter search term and get page title
-    Given I am on the website 'http://www.google.com'
-    When I submit the search term 'BrowserStack'
-    Then the page title should be 'BrowserStack - Google Search'
\ No newline at end of file
diff --git a/src/test/resources/features/test/StackDemo.feature b/src/test/resources/features/test/StackDemo.feature
new file mode 100644
index 0000000..f0df316
--- /dev/null
+++ b/src/test/resources/features/test/StackDemo.feature
@@ -0,0 +1,6 @@
+Feature: BrowserStack Demo
+
+  Scenario: BStack Sample Test - Add product to cart
+    Given I am on the website 'https://www.bstackdemo.com'
+    When I select a product and click on 'Add to cart' button
+    Then the product should be added to cart
diff --git a/src/test/resources/testng.xml b/src/test/resources/testng.xml
new file mode 100644
index 0000000..28c168b
--- /dev/null
+++ b/src/test/resources/testng.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
+<suite name="BDD Test Suite" verbose="1">
+    <test name="Cucumber Tests">
+        <classes>
+            <class name="com.browserstack.RunWebDriverCucumberTests" />
+        </classes>
+    </test>
+</suite>
