← Blog

"Selenium Series #14: Cross-Browser Testing — Chrome, Firefox, Safari, Edge"

Run the exact same test suite across four browsers simultaneously. Configure parallel cross-browser execution in testng.xml, handle browser-specific quirks, and build browser-agnostic test code.

reading now
views
comments

Series Navigation

Part 13: Data-Driven Testing

Part 15: Selenium Grid — Parallel Execution at Scale


The Cross-Browser Testing Strategy

Your app must work in every browser your users use. Chrome has ~65% market share, but the rest matters:

Browser Engine Market Share
Chrome Blink ~65%
Safari WebKit ~19%
Edge Blink ~4%
Firefox Gecko ~4%

Run critical flows on all browsers. Run full regression on Chrome.


testng.xml — Parallel Browser Configuration

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">

<suite name="Cross Browser Suite" parallel="tests" thread-count="4">

    <test name="Chrome Tests">
        <parameter name="browser" value="chrome"/>
        <parameter name="headless" value="false"/>
        <packages>
            <package name="com.yourname.selenium.tests"/>
        </packages>
    </test>

    <test name="Firefox Tests">
        <parameter name="browser" value="firefox"/>
        <parameter name="headless" value="false"/>
        <packages>
            <package name="com.yourname.selenium.tests"/>
        </packages>
    </test>

    <test name="Edge Tests">
        <parameter name="browser" value="edge"/>
        <parameter name="headless" value="false"/>
        <packages>
            <package name="com.yourname.selenium.tests"/>
        </packages>
    </test>

    <!-- Safari — macOS only, must enable Remote Automation in Safari preferences -->
    <test name="Safari Tests">
        <parameter name="browser" value="safari"/>
        <packages>
            <package name="com.yourname.selenium.tests"/>
        </packages>
    </test>

</suite>

Update BaseTest to read the browser parameter:

@BeforeMethod
@Parameters({"browser", "headless"})
public void setUp(
    @Optional("chrome") String browser,
    @Optional("false") String headless
) {
    boolean isHeadless = Boolean.parseBoolean(headless);
    WebDriver driver   = DriverFactory.createDriver(browser, isHeadless);
    driverThreadLocal.set(driver);
}

Updated DriverFactory

public class DriverFactory {

    public static WebDriver createDriver(String browser, boolean headless) {
        switch (browser.toLowerCase().trim()) {
            case "chrome":   return createChrome(headless);
            case "firefox":  return createFirefox(headless);
            case "edge":     return createEdge(headless);
            case "safari":   return createSafari();
            default:
                throw new IllegalArgumentException("Unknown browser: " + browser);
        }
    }

    private static WebDriver createChrome(boolean headless) {
        WebDriverManager.chromedriver().setup();
        ChromeOptions opts = new ChromeOptions();
        opts.addArguments("--start-maximized", "--disable-notifications",
                          "--no-sandbox", "--disable-dev-shm-usage");
        if (headless) {
            opts.addArguments("--headless", "--window-size=1920,1080");
        }
        return new ChromeDriver(opts);
    }

    private static WebDriver createFirefox(boolean headless) {
        WebDriverManager.firefoxdriver().setup();
        FirefoxOptions opts = new FirefoxOptions();
        if (headless) opts.setHeadless(true);
        opts.addArguments("--width=1920", "--height=1080");
        return new FirefoxDriver(opts);
    }

    private static WebDriver createEdge(boolean headless) {
        WebDriverManager.edgedriver().setup();
        EdgeOptions opts = new EdgeOptions();
        opts.addArguments("--start-maximized", "--disable-notifications");
        if (headless) opts.addArguments("--headless", "--window-size=1920,1080");
        return new EdgeDriver(opts);
    }

    private static WebDriver createSafari() {
        // Safari requires: Safari > Preferences > Advanced > Show Develop menu
        // Then: Develop > Allow Remote Automation
        return new SafariDriver();
    }
}

Browser-Specific Quirks and Workarounds

Safari — No Headless Mode

// Safari does NOT support headless mode (as of 2021)
// Always runs with visible browser window on macOS
if (browser.equals("safari") && headless) {
    System.out.println("Warning: Safari does not support headless. Running headed.");
    // Just create normal SafariDriver
}

Firefox — sendKeys Difference

// Some special characters work differently in Firefox
// Use Actions.sendKeys for reliability in Firefox
Actions actions = new Actions(driver);
actions.click(inputField)
       .sendKeys("test@example.com")
       .perform();

Edge — Legacy vs Chromium

// Edge Chromium (2020+): use EdgeDriver + WebDriverManager.edgedriver()
// Edge Legacy (pre-2020): use different driver — essentially deprecated
// Always target Chromium-based Edge

Cross-Browser Wait Consistency

// Some browsers are slower to process certain events
// Increase wait timeout for cross-browser suites
int timeout = browser.equals("safari") ? 20 : 10;
WebDriverWait wait = new WebDriverWait(driver, timeout);

Run From Command Line With Browser Override

# Run on specific browser from command line
mvn test -Dbrowser=firefox -Dheadless=true

# Run on all browsers using cross-browser suite
mvn test -DsuiteXmlFile=src/test/resources/cross-browser-testng.xml

What's Next

In Part 15 we scale to dozens of parallel sessions with Selenium Grid — running tests across multiple machines, browsers, and operating systems simultaneously.

Discussion

Loading...

Leave a Comment

All comments are reviewed before appearing. No links please.

0 / 1000