Using Selenium with Firefox Snap (Ubuntu)
Ubuntu now provides Firefox as a Snap package. The WebDriver for Firefox (geckodriver) is not compatible out-of-box. From the release notes:
Using geckodriver to launch Firefox inside a sandbox -- for example a Firefox distribution using Snap or Flatpak -- can fail with a "Profile not found" error if the sandbox restricts Firefox's ability to access the system temporary directory. geckodriver uses the temporary directory to store Firefox profiles created during the run.
They provide a work around:
This issue can now be worked around by using the --profile-root command line option or setting the TMPDIR environment variable to a location that both Firefox and geckodriver have read/write access
How do you pass --profile-root to geckodriver from Selenium? It isn't trivial but here's one way to do it:
import java.io.File; import java.util.ArrayList; import java.util.List; import org.openqa.selenium.firefox.FirefoxDriver; import org.openqa.selenium.firefox.FirefoxOptions; import org.openqa.selenium.firefox.GeckoDriverService; public final class DriverUtil { private DriverUtil() { } public static FirefoxDriver getFirefoxDriver() { FirefoxOptions options = new FirefoxOptions(); String osName = System.getProperty("os.name"); String profileRoot = osName.contains("Linux") && new File("/snap/firefox").exists() ? createProfileRootInUserHome() : null; return profileRoot != null ? new FirefoxDriver(createGeckoDriverService(profileRoot), options) : new FirefoxDriver(options); } private static String createProfileRootInUserHome() { String userHome = System.getProperty("user.home"); File profileRoot = new File(userHome, "snap/firefox/common/.firefox-profile-root"); if (!profileRoot.exists()) { if (!profileRoot.mkdirs()) { return null; } } return profileRoot.getAbsolutePath(); } private static GeckoDriverService createGeckoDriverService(String tempProfileDir) { return new GeckoDriverService.Builder() { @Override protected List<String> createArgs() { List<String> args = new ArrayList<>(super.createArgs()); args.add(String.format("--profile-root=%s", tempProfileDir)); return args; } }.build(); } }
The above example uses "~/snap/firefox/common/.firefox-profile-root" as the profile root but you can choose some other directory under "~/snap/firefox/common/" as desired.
Comments
-
Another workaround from Running Firefox in a container-based package:
Use a geckodriver that runs in the same container filesystem as the Firefox package. For example on Ubuntu /snap/bin/geckodriver will work with the default Firefox.
However, making this work involves overriding File.getCanonicalPath() as described here:
https://github.com/SeleniumHQ/selenium/issues/7788Example:
public static FirefoxDriver getFirefoxDriver() { FirefoxOptions options = new FirefoxOptions(); GeckoDriverService service = null; File snapGeckoDriver = new File("/snap/bin/geckodriver") { // https://github.com/SeleniumHQ/selenium/issues/7788 @Override public String getCanonicalPath() throws IOException { return getAbsolutePath(); } }; if (snapGeckoDriver.exists()) { service = new GeckoDriverService.Builder().usingDriverExecutable(snapGeckoDriver).build(); } return service != null ? new FirefoxDriver(service, options) : new FirefoxDriver(options); }
0