Hero Background

Power Your Software Testing with AI Agents and Cloud

The Native AI-Agentic Cloud Platform to Supercharge Quality Engineering. Test Intelligently and Ship Faster.

AutomationSelenium JavaTutorial

How To Perform Local Website Testing Using Selenium And Java

Local website testing with Selenium Java: run TestNG tests on cloud Chrome and Safari through the TestMu AI tunnel, with fixes for common tunnel errors.

Last Updated on:

Local website testing checks a site while it still runs on your own machine, before it reaches staging or production. Cloud browsers complicate that: localhost on a cloud machine points at that machine, so a Selenium session on a remote grid cannot open http://localhost:8000 on your laptop until something routes the request back to you.

TestMu AI local page testing provides that route through an encrypted tunnel. Every run in this guide happened on September 30, 2026: one TestNG test against a page served from a Windows laptop, on Chrome 154 (Windows 11) and Safari 18.5 (macOS Sequoia), with the real output kept below.

The runs also hit problems, each with a tested fix later in this guide: Maven Surefire 3.6.0 ignoring testng.xml, a tunnel name still held after a force-quit, the tunnel carrying the browsers' background traffic, and a Vite dev server rejecting the tunnel's fallback host name.

Overview

To test a local website with Selenium and Java on cloud browsers, serve the site on a localhost port, start the TestMu AI tunnel with a --tunnelName, and set tunnel and tunnelName in LT:Options. RemoteWebDriver then opens http://localhost:8000 from cloud Chrome or Safari, and TestNG runs the suite with mvn test.

  • Local Website Testing: Local website testing runs functional and cross-browser checks against a site served from a developer's machine, such as http://localhost:8000, before the code is deployed to staging or production.
  • TestMu AI Tunnel: The TestMu AI tunnel connects cloud browsers to a site on your machine over an encrypted connection, without a public URL. In the runs for this guide, tunnel version 3.2.36 connected over TCP on port 443. Public URL required: No.
  • Tunnel Capabilities: Setting tunnel to true in LT:Options sends a Selenium session through a tunnel, and tunnelName selects which running tunnel to use, so it must match the --tunnelName value the tunnel was started with.
  • Host Allowlist: The --allowHosts flag limits which hosts go through the tunnel. With default flags, the tunnel carried 21 background requests from the cloud browsers to 13 third-party hosts, while --allowHosts localhost left only the 4 localhost requests.
  • Surefire Version: Maven Surefire 3.6.0 removed its TestNG provider and ignores testng.xml, so a suite that passes browser parameters through testng.xml needs maven-surefire-plugin pinned to a 3.5.x release such as 3.5.6.
  • Tunnel in CI: A CI job can start the tunnel from TestNG with the lambdatest-tunnel-binary Maven package, or run the tunnel binary in the background with --infoAPIPort and stop it with DELETE /api/v1.0/stop, which releases the tunnel name.
  • Dev Server Host Checks: Dev servers that validate the Host header, such as Vite 8.3.1, reject the fallback host localhost.lambdatest.com until it is added to server.allowedHosts, while http://localhost URLs load through the tunnel unchanged.

What Is Local Website Testing?

Local website testing is website testing (functional and cross-browser checks) run against a site served from a developer's machine, usually at an address like http://localhost:8000, before the code is deployed to a shared environment. A change can be tested as soon as the local server picks it up, without waiting for a deploy.

Localhost is the loopback address (127.0.0.1) that always refers to the machine making the request, so only browsers on that machine can load it without extra setup. Local testing is the first stop in the usual order of test environments:

EnvironmentWhere it runsWho can reach itWhat you test there
LocalYour machine, at a localhost addressYou, plus cloud browsers that come in through a tunnelFunctional and cross-browser checks on changes that are not merged yet
StagingA shared server that mirrors productionYour team, often behind a firewallRegression testing and integration testing with real services
ProductionPublic serversEvery userSmoke tests and monitoring

How to Test a Local Website on Other Browsers

Checking cross browser compatibility means reaching the local site from browsers you do not have installed. The options differ in who else can reach the site while you test:

ApproachBrowser coverageWho can reach the siteFits when
Local browsers onlyBrowsers installed on your machineOnly youQuick checks while you code
Public tunnel service, such as ngrokAny browser that opens the public URLAnyone with the URLSharing a preview or receiving webhooks
Cloud grid tunnel (TestMu AI)3,000+ browser and OS combinationsOnly cloud sessions that use your tunnelAutomated cross-browser tests before a deploy
Deploy to stagingAny browser that can reach stagingYour network or allowlisted IP addressesRegression runs on a stable build

The cloud grid tunnel is the row that combines broad browser coverage with no public URL and no deploy, so the rest of this guide uses it. For layout checks at different screen sizes, the guide to responsive testing of a locally hosted website covers the manual side.

Note

Note: Test your localhost site on 3,000+ browser and OS combinations without deploying it or giving it a public URL. Try TestMu AI free

How to Set Up the Local Site and the Tunnel

The setup has two parts: a server that serves the site on a localhost port, and the tunnel client that connects your machine to the TestMu AI grid. Both must be running before the first test starts.

Serve the Site on Localhost

Any local server works, whether it is jwebserver, a framework dev server, or XAMPP, as long as you know its port. The demo is a single page whose toggle switches an Email alerts label from OFF to ON, which gives the test a state to assert. Save it as index.html:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Local Toggle Demo</title>
  <style>
    body { font-family: sans-serif; text-align: center; margin-top: 80px; }
    #cb1 { display: none; }
    .toggle { display: inline-block; width: 56px; height: 30px; border-radius: 15px; background: #ccc; cursor: pointer; position: relative; }
    .toggle::after { content: ""; position: absolute; top: 3px; left: 3px; width: 24px; height: 24px; border-radius: 50%; background: #fff; transition: left 0.2s; }
    #cb1:checked + .toggle { background: #22c55e; }
    #cb1:checked + .toggle::after { left: 29px; }
  </style>
</head>
<body>
  <h1>Notification Settings</h1>
  <input type="checkbox" id="cb1">
  <label for="cb1" class="toggle"></label>
  <p>Email alerts: <span id="status">OFF</span></p>
  <script>
    document.getElementById("cb1").addEventListener("change", function (e) {
      document.getElementById("status").textContent = e.target.checked ? "ON" : "OFF";
    });
  </script>
</body>
</html>

JDK 18 and later include jwebserver, the static file server added by JEP 408, so a Java project needs no extra install. The JEP describes it as binding to 127.0.0.1 by default and serving static files over HTTP only, which is all this demo needs. Run it from the folder that holds index.html:

jwebserver -p 8000

For Python or PHP projects, the MDN guide to local testing servers covers python -m http.server and PHP's built-in server.

Start the TestMu AI Tunnel

Download the tunnel binary for your operating system from the Test Locally Hosted Web Pages docs, which list Windows, macOS, Linux, and FreeBSD builds. Start it with your username, your access key (both in the Credentials section of the TestMu AI dashboard), and a tunnel name:

LT --user <your-username> --key <your-access-key> --tunnelName local-website-testing

On Windows the binary is LT.exe. The setup guides for Windows, macOS, and Linux cover installation details, and Underpass starts the same tunnel from a desktop app if you prefer to skip the command line.

The command above printed this output once the tunnel was ready:

No configuration file found. Proceeding with defaults
INFO	LambdaTest Tunnel version: 3.2.36
INFO	Tunnel binary started on port :9090
INFO	TCP Mode is supported
INFO	Launching tunnel
INFO	Tcp data connections rotate after 3000s
INFO	Server enabled capabilities: tcp-multi-stream, tcp-stream-rotate
INFO	Using 5 tcp data connection(s)
INFO	You can start testing now
INFO	Tunnel ID: 17617416

Tunnel 3.2.36 connected over TCP on port 443; with --verbose, the log also shows "Trying TCP on port 443" and "TLS handshake completed successfully in TCP Mode". The 2023 version of this guide showed an SSH connection over port 22 instead, and the tunnel flags reference lists --mode with ssh, tcp, and ws values for networks that block one of them.

The tunnelName capability in the test must match --tunnelName, and one name can belong to only one running tunnel at a time, which matters once CI jobs start tunnels in parallel.

Route Only Localhost Through the Tunnel

By default, the tunnel also carried the cloud browsers' own background calls, so those requests left through the laptop's network. The tunnel log from two runs of the same suite showed:

  • Default flags - 25 proxied requests: 4 to localhost and 21 to 13 other hosts, including www.google.com, accounts.google.com, and configuration.apple.com.
  • --allowHosts localhost - 4 proxied requests, all to localhost, and both tests still passed.

The advanced tunnel features page describes --allowHosts as routing "only requests for provided domains" through the tunnel. Add any other internal host the page calls to the comma-separated list:

LT --user <your-username> --key <your-access-key> --tunnelName local-website-testing --allowHosts localhost

Check the Site in Real-Time Testing

Before writing automation, you can confirm the route by hand in Real-Time Testing: enable the tunnel, select your tunnel name if more than one is running, enter http://localhost:8000, and start a session on any browser and OS. If the page loads, the route works, and this short walkthrough shows the flow:

Youtube thumbnail

How to Run Selenium Java Tests Against Localhost

The test opens the local page in a cloud browser, clicks the toggle, and asserts that the status reads ON. TestNG runs it on Chrome and Safari in parallel. If you are new to Selenium with Java, install a JDK (17 or later) and Maven first, and use the Selenium tutorials for the rest of the WebDriver API.

Add Selenium and TestNG to pom.xml

The pom.xml pins the versions used in these runs, Selenium 4.49.0 and TestNG 7.12.0, plus a Surefire version that still runs TestNG suite files:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>local-website-testing</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.release>17</maven.compiler.release>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>4.49.0</version>
        </dependency>
        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>7.12.0</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.5.6</version>
                <configuration>
                    <suiteXmlFiles>
                        <suiteXmlFile>testng.xml</suiteXmlFile>
                    </suiteXmlFiles>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

The Surefire 3.6.0 release notes list surefire-testng among the removed provider modules and say the suiteXmlFiles configuration for TestNG "is no longer supported"; they also say you can stay on the 3.5.x line.

This pom.xml uses 3.5.6, the newest 3.5.x release on Maven Central when these runs happened. On 3.6.0, the same project skipped testng.xml and its parameters, as the troubleshooting section shows.

Write the Test

Save the class as src/test/java/LocalWebsiteTest.java. It reads the credentials from the LT_USERNAME and LT_ACCESS_KEY environment variables and the tunnel name from LT_TUNNEL_NAME, falling back to local-website-testing:

import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.AbstractDriverOptions;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.safari.SafariOptions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.Assert;
import org.testng.ITestResult;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;

import java.net.URL;
import java.time.Duration;
import java.util.HashMap;

public class LocalWebsiteTest {

    // The address of the site on your machine; the tunnel makes it reachable from the cloud browser.
    private static final String LOCAL_URL = System.getProperty("localUrl", "http://localhost:8000/");

    private WebDriver driver;
    private WebDriverWait wait;
    private String browser;

    @BeforeMethod
    @Parameters({"browser", "platform"})
    public void setUp(String browser, String platform) throws Exception {
        this.browser = browser;
        AbstractDriverOptions<?> options = browser.equals("Safari") ? new SafariOptions() : new ChromeOptions();
        options.setBrowserVersion("latest");
        options.setPlatformName(platform);

        HashMap<String, Object> ltOptions = new HashMap<>();
        ltOptions.put("username", System.getenv("LT_USERNAME"));
        ltOptions.put("accessKey", System.getenv("LT_ACCESS_KEY"));
        ltOptions.put("build", "Local Website Testing");
        ltOptions.put("name", "Toggle test - " + browser);
        ltOptions.put("tunnel", true);
        ltOptions.put("tunnelName", System.getenv().getOrDefault("LT_TUNNEL_NAME", "local-website-testing"));
        ltOptions.put("w3c", true);
        options.setCapability("LT:Options", ltOptions);

        driver = new RemoteWebDriver(new URL("https://hub.lambdatest.com/wd/hub"), options);
        wait = new WebDriverWait(driver, Duration.ofSeconds(15));
    }

    @Test
    public void toggleTurnsEmailAlertsOn() {
        driver.get(LOCAL_URL);
        wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("label[for='cb1']"))).click();
        wait.until(ExpectedConditions.textToBe(By.id("status"), "ON"));
        Assert.assertTrue(driver.findElement(By.id("cb1")).isSelected(), "cb1 should be checked");
        System.out.println(browser + " loaded " + driver.getCurrentUrl() + " and the toggle reads ON");
    }

    @AfterMethod
    public void tearDown(ITestResult result) {
        if (driver != null) {
            ((JavascriptExecutor) driver).executeScript("lambda-status=" + (result.isSuccess() ? "passed" : "failed"));
            driver.quit();
        }
    }
}

Run Chrome and Safari in Parallel

The testng.xml file runs the class once per browser, in parallel:

<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Local Website Testing" parallel="tests" thread-count="2">
    <test name="Chrome on Windows 11">
        <parameter name="browser" value="Chrome"/>
        <parameter name="platform" value="Windows 11"/>
        <classes><class name="LocalWebsiteTest"/></classes>
    </test>
    <test name="Safari on macOS">
        <parameter name="browser" value="Safari"/>
        <parameter name="platform" value="macOS Sequoia"/>
        <classes><class name="LocalWebsiteTest"/></classes>
    </test>
</suite>

With the tunnel running and the credentials exported, run the suite:

mvn test

Both browsers passed in under 20 seconds (output trimmed to the test lines):

[INFO] Running TestSuite
Chrome loaded http://localhost:8000/ and the toggle reads ON
Safari loaded http://localhost:8000/ and the toggle reads ON
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 18.56 s -- in TestSuite
[INFO] BUILD SUCCESS

Each session's record in the automation API carries the tunnel ID from the tunnel output above, which confirms the traffic went through that tunnel. An excerpt for the Safari session:

{
  "build_name": "Local Website Testing",
  "name": "Toggle test - Safari",
  "status_ind": "passed",
  "browser": "safari",
  "platform": "sequoia",
  "tunnel": true,
  "tunnel_id": 17617416,
  "tunnel_name": "local-website-testing"
}

Code Walkthrough

  • tunnel and tunnelName - tunnel set to true sends the session through a tunnel, and tunnelName picks which one. Without them, the cloud browser resolves localhost to its own machine.
  • RemoteWebDriver - the RemoteWebDriver sends commands to the TestMu AI hub instead of a local browser driver, and the username and access key travel inside LT:Options.
  • AbstractDriverOptions - ChromeOptions and SafariOptions share this parent class, so one setUp method builds either one from the browser parameter.
  • @BeforeMethod and @AfterMethod - these run before and after each test method, so every test gets a fresh session. The 2023 version of this code used @BeforeTest, which runs once before the classes inside a testng.xml test tag, not before each method, as the guide to TestNG annotations explains.
  • Explicit waits and an assertion - the test waits for the toggle to be clickable and for the status to read ON, then asserts the checkbox state. The toggle is found by its CSS selector, label[for='cb1'].
  • lambda-status - the executeScript call in tearDown marks the session passed or failed on the dashboard, based on TestNG's ITestResult.
Austin Siewert

Austin Siewert

Co-Founder, Steadfast Systems

Discovered @TestMu AI yesterday. Best browser testing tool I've found for my use case. Great pricing model for the limited testing I do 👏

2M+ Devs and QAs rely on TestMu AI

Deliver immersive digital experiences with Next-Generation Mobile Apps and Cross Browser Testing Cloud

How to Start the Tunnel From Java Code or CI

A tunnel started by hand works on a laptop. In a CI/CD pipeline, it has to start before the tests, use a name no parallel job is using, and stop even when a test fails.

Start It From TestNG With the Maven Tunnel

The Maven tunnel package, lambdatest-tunnel-binary 4.0.2, downloads the tunnel binary and controls it from Java. Add it to pom.xml:

<dependency>
    <groupId>com.github.lambdatest</groupId>
    <artifactId>lambdatest-tunnel-binary</artifactId>
    <version>4.0.2</version>
    <scope>test</scope>
</dependency>

Start and stop it in suite-level hooks, with the same tunnel name and --allowHosts value as before:

import com.lambdatest.tunnel.Tunnel;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeSuite;

import java.util.HashMap;

public class TunnelSetup {

    private static Tunnel tunnel;

    @BeforeSuite
    public void startTunnel() throws Exception {
        tunnel = new Tunnel();
        HashMap<String, String> options = new HashMap<>();
        options.put("user", System.getenv("LT_USERNAME"));
        options.put("key", System.getenv("LT_ACCESS_KEY"));
        options.put("tunnelName", System.getenv().getOrDefault("LT_TUNNEL_NAME", "local-website-testing"));
        options.put("allowHosts", "localhost");
        tunnel.start(options);
    }

    @AfterSuite(alwaysRun = true)
    public void stopTunnel() throws Exception {
        if (tunnel != null) {
            tunnel.stop();
        }
    }
}

Then add the class to testng.xml as its own test block, before the browser tests:

<test name="Tunnel lifecycle">
    <classes><class name="TunnelSetup"/></classes>
</test>

A plain mvn test then handles the whole tunnel lifecycle. The suite took about 31 seconds instead of under 20, because the tunnel now starts inside the run:

Tunnel Started Successfully
Tunnel ID: 17616167
Chrome loaded http://localhost:8000/ and the toggle reads ON
Safari loaded http://localhost:8000/ and the toggle reads ON
Tunnel closed successfully && Port process killed
Tunnel process terminated successfully.
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 30.76 s -- in TestSuite

Run the Tunnel Binary in a CI Job

For non-Java suites, or to keep the tunnel in its own step, start the binary in the background and control it through its info API. This script, run as written for this guide, gives each job its own tunnel name and stops the tunnel on exit, pass or fail:

#!/usr/bin/env bash
set -e
export LT_TUNNEL_NAME="ci-${GITHUB_RUN_ID:-local}"

./LT --user "$LT_USERNAME" --key "$LT_ACCESS_KEY" \
  --tunnelName "$LT_TUNNEL_NAME" --allowHosts localhost --infoAPIPort 9091 &
trap 'curl -s -X DELETE http://127.0.0.1:9091/api/v1.0/stop' EXIT

for i in $(seq 1 30); do
  curl -s http://127.0.0.1:9091/api/v1.0/info | grep -q '"status":"SUCCESS"' && break
  sleep 2
done

mvn test

The --infoAPIPort flag exposes GET /api/v1.0/info and DELETE /api/v1.0/stop, both documented on the advanced tunnel features page. Without that flag the tunnel has no info API to call, since port 9090 in its output is the local proxy. In one run a compile error failed the job, and the trap still stopped the tunnel, so the next run could reuse its name.

On GitHub Actions, the tunnel GitHub Action setup guide covers LambdaTest/LambdaTest-tunnel-action@v2, which starts and tears down the tunnel from user, accessKey, and tunnelName inputs.

Let HyperExecute Start the Tunnel

On HyperExecute, setting tunnel: true in the job YAML spawns a tunnel at runtime, and tunnelNames reuses tunnels that are already running; the HyperExecute tunnel configuration guide lists the options. HyperExecute can also start your app server as a background service on the test VM, the approach in this walkthrough on testing locally hosted websites with HyperExecute background services.

Troubleshooting Local Website Tests

Most of these failures came up in the runs for this guide, with the exact messages shown. The tunnel troubleshooting guide covers more cases, such as WordPress CSS not loading and IP allowlisting.

Maven Ignores testng.xml

On Surefire 3.6.0, the first run failed before any browser started:

[WARNING]  Parameter 'suiteXmlFiles' (user property 'surefire.suiteXmlFiles') is deprecated: not supported after 3.6.0, please use groups or Junit suite support
[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
[INFO] TestNG is present. Adding per default org.junit.support:testng-engine:1.1.0
Parameter 'browser' is required by BeforeMethod on method setUp but has not been marked @Optional or defined

Surefire 3.6.0 runs TestNG through the JUnit Platform testng-engine, which does not load the suite file, so the browser and platform parameters are never set. Pin the plugin to a 3.5.x release, as the pom.xml above does, or replace the suite file with TestNG groups as the release notes suggest.

Tunnel Name Conflict After a Force-Quit

After the tunnel process was force-killed, restarting it with the same name failed:

ERROR	conflict: Tunnel with name: local-website-testing is already running for another user
ERROR	There was an error while starting tunnel: ERR::LUNCH::TUNN : Launch tunnel failed conflict: Tunnel with name: local-website-testing is already running for another user
INFO	Mode "tcp" failed, adding to excluded modes

The server still listed the killed tunnel as running a few minutes later. Stop tunnels through the info API (curl -X DELETE http://127.0.0.1:9091/api/v1.0/stop, with the port you passed to --infoAPIPort) instead of killing the process.

For a tunnel that is already orphaned, the automation API stops it by ID, and a GET on the same tunnels endpoint lists running tunnels with their IDs. This DELETE call cleared the orphaned tunnel at once:

curl -X DELETE -u "<username>:<access-key>" https://api.lambdatest.com/automation/api/v1/tunnels/<tunnel-id>

Unique names per job, as in the CI script above, keep parallel jobs from colliding in the first place.

Locator Timeouts When the Tunnel Is Down

While that conflict kept the tunnel down, the Selenium sessions still started, and both tests failed with an ordinary locator timeout instead of a tunnel error:

Expected condition failed: waiting for element found by By.cssSelector: label[for='cb1'] to be clickable, but the element was not found: org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"css selector","selector":"label[for='cb1']"}.

When every browser fails on its first locator, check that the tunnel printed "You can start testing now", or query the info API, before debugging selectors. The tunnel troubleshooting guide lists the matching browser error as ERR_TUNNEL_CONNECTION_FAILED.

Localhost Refused to Connect

The tunnel troubleshooting guide says the localhost URL "is unfortunately not compatible with various browsers and browser versions" and recommends localhost.lambdatest.com or your machine's IP address instead, for example http://localhost.lambdatest.com:8000/. In the runs for this guide, Chrome 154 and Safari 18.5 both loaded http://localhost:8000/ directly, and the local server logged Host: localhost:8000 from both.

The fallback name works too: http://localhost.lambdatest.com:8000/ reached the same jwebserver through the tunnel from Chrome. Switch to it only when a browser shows this error, because dev servers can reject it, as the next section shows.

Blocked Request or Invalid Host Header

Dev servers that check the Host header reject names they do not know. Through the tunnel, Vite 8.3.1 served http://localhost:5173/ but answered http://localhost.lambdatest.com:5173/ with:

Blocked request. This host ("localhost.lambdatest.com") is not allowed. To allow this host, add "localhost.lambdatest.com" to `server.allowedHosts` in vite.config.js.

The Vite server options docs allow only localhost, domains under .localhost, and IP addresses by default, as a defense against DNS rebinding.

Adding the host to allowedHosts and restarting the dev server fixed it in the next run:

import { defineConfig } from "vite";

export default defineConfig({
  server: {
    allowedHosts: ["localhost.lambdatest.com"],
  },
});

Do not set allowedHosts to true: the Vite docs warn that it lets any website send requests to your dev server through DNS rebinding attacks. The tunnel troubleshooting guide lists the fixes for Angular and React projects, where the same problem shows up as "Invalid Host Header".

Firewalls and Self-Signed Certificates

If the tunnel cannot connect, the troubleshooting guide suggests --sshConnType over_443 or --mode ws when an SSH connection over port 22 is blocked, and the --proxy-host and --proxy-port flags when traffic must go through a corporate proxy. For a local site on HTTPS with a self-signed certificate, the Selenium localhost testing docs recommend starting the tunnel with --mitm.

How Can AI Coding Assistants Write Tunnel-Ready Selenium Tests?

If Claude Code, GitHub Copilot, Cursor, or Gemini CLI writes your Selenium tests, the Selenium Skill gives the assistant the patterns this guide used. It is part of the open-source TestMu AI agent skills collection, and one command adds it to a project:

npx agentskillsforall add https://github.com/LambdaTest/agent-skills.git --skill selenium-skill

Its rules match the test above:

  • Explicit waits only - the skill marks its wait strategy as critical and tells the assistant to "ALWAYS use explicit waits", which is why the test waits for the toggle and the status text instead of sleeping.
  • Credentials from the environment - its validation checklist requires LT_USERNAME and LT_ACCESS_KEY from environment variables.
  • Tunnel capability - its cloud reference lists tunnel ("true for localhost") and tunnelName in LT:Options, the two keys this test depends on.
  • Pass or fail on the dashboard - its TestNG base class reports lambda-status from ITestResult in @AfterMethod, as this test does.

Install the Selenium Skill so Claude Code, Copilot, and Cursor write tunnel-ready Selenium tests with explicit waits.

Selenium

Conclusion

For local website testing on your own project, point the suite from this guide at your localhost port: start the tunnel with a unique --tunnelName, set tunnel and tunnelName in LT:Options, and run mvn test. Automation Cloud records video, network logs, and console logs for every session, so a Safari failure on a local build can be debugged from a Windows machine.

To grow the matrix beyond two browsers, the Selenium with TestNG docs include a sample project whose testng.xml runs the test across multiple browsers at once.

Author

...

Vipul Gupta

Blogs: 24

  • Twitter
  • Linkedin

Vipul Gupta is a Sr. Lead SDET at Zupee with over 9 years of experience in functional and automation testing. He has built 10+ automation projects from scratch covering web, API, and mobile applications. Vipul is skilled in Selenium, Appium, Rest Assured, Playwright, Java, Python, Pytest, BDD, TDD, Maven, Jenkins, TestNG, and JUnit. He has successfully led end-to-end QA efforts, including setting up teams from scratch and managing a 15-member QA team to ensure manual and automation testing run in parallel from day one. Vipul graduated in B.Tech CSE from CGC College of Engineering and is followed by 3,000+ QA and SDET professionals on LinkedIn, reflecting his strong influence in the testing community.

Reviewer

...

Sawan Garg

Reviewer

  • Linkedin

Sawan Garg is Senior Vice President of Engineering at TestMu AI (formerly LambdaTest), leading platform and infrastructure engineering across the testing cloud. He designed the microservices architecture and databases behind the platform and built the streaming technologies, including VNC, Guacamole, and WebRTC, that deliver live and real-time testing. He also contributed to the distributed proxy-based Tunnel that lets teams test firewall-protected and locally hosted websites. He brings 13+ years of engineering experience across Python, Java, Golang, Node.js, Kafka, Elasticsearch, Redis, and Kubernetes. Sawan holds a B.Tech in Computer Science and Engineering.

Add to Google preferred sources

Summarise with AI

Copied to Clipboard!
...

3000+ Browsers. One Platform.

See exactly how your site performs everywhere.

Try it free
...

Write Tests in Plain English with KaneAI

Create, debug, and evolve tests using natural language.

Try for free

Local Website Testing FAQs

Did you find this page helpful?

More Related Blogs

TestMu AI forEnterprise

Get access to solutions built on Enterprise
grade security, privacy, & compliance

  • Advanced access controls
  • Advanced data retention rules
  • Advanced Local Testing
  • Premium Support options
  • Early access to beta features
  • Private Slack Channel
  • Unlimited Manual Accessibility DevTools Tests