Specify a custom user data directory in Firefox using Watir-Webdriver/Selenium Specify a custom user data directory in Firefox using Watir-Webdriver/Selenium selenium selenium

Specify a custom user data directory in Firefox using Watir-Webdriver/Selenium


This is for firefox 60+ and the new marionette/geckodriver.

After fiddling a lot, this is how I got it working with a custom profile:

$ xvfb-run firefox -CreateProfile testoptions = Selenium::WebDriver::Firefox::Options.new # no profile specified hereoptions.add_argument "--profile"options.add_argument "/home/jenkins/.mozilla/firefox/f0jecsmr.test"@browser = Watir::Browser.new :firefox, options: options, driver_opts: {marionette_port: 2828}, **capabilities

It is close to how documentation suggests to do with python. It took reading the source to figure out these driver_opts though (or I didn't find relevant documentation).

HTH somebody.


Based on Selenium Issue 1954 and Issue 7374, the Firefox driver does not currently have this functionality. It is hard to tell if it will be implemented given that some of the project members are opposing the idea.

For now, I think you will have to monkey-patch your Selenium-WebDiver version to add this functionality. I reached the same conclusion as @shri046's answer, which is to modify the layout_on_disk method.

After you have required Selenium-WebDriver, add the following monkey patch for the Selenium::WebDriver::FirefoxProfile. The logic in this patch is that:

  • If a profile directory is not specified, use the normal/existing behaviour, which means copying an existing profile and deleting it on exit.
  • If a profile directory is specified:
    • If the directory exists, use that directory for the profile. It is assumed that the directory is a valid profile (ie I did not add checks to ensure it was valid).
    • If the directory does not exist, a copy of an existing profile will be created (ie the normal behaviour). This profile will then be moved to the specified directory. The profile is not deleted on exit and therefore can be re-used again later.

Patch:

require 'watir-webdriver'require 'selenium-webdriver'module Selenium  module WebDriver    module Firefox      class Profile        class << self          attr_accessor :webdriver_profile_directory        end        def layout_on_disk          # When a directory is specified, ensure it is not deleted at exit          if Profile.webdriver_profile_directory            FileReaper.reap = false          end          # Use the specified directory if it already exists (ie assuming an existing profile)          if Profile.webdriver_profile_directory && Dir.exists?(Profile.webdriver_profile_directory)            return Profile.webdriver_profile_directory          end          # Create the profile directory as usual when it does not exist          profile_dir = @model ? create_tmp_copy(@model) : Dir.mktmpdir("webdriver-profile")          FileReaper << profile_dir          install_extensions(profile_dir)          delete_lock_files(profile_dir)          delete_extensions_cache(profile_dir)          update_user_prefs_in(profile_dir)          # If a directory is specified, move the created profile to that directory          if Profile.webdriver_profile_directory            FileUtils.cp_r(profile_dir, Profile.webdriver_profile_directory)            profile_dir = Profile.webdriver_profile_directory          end          profile_dir        end      end # Profile    end # Firefox  end # WebDriverend # Selenium

To specify the profile location to use do the following:

Selenium::WebDriver::Firefox::Profile.webdriver_profile_directory = 'C:/temp/test-profile'browser = Watir::Browser.new :firefox

This patch may have limitations and untested areas. For example, it probably will not handle creating multiple instances of Firefox. However, for a single instance, it at least seems to work with reloading bookmarks created (which was the limit of my testing).


Looking at the source code for Firefox profile it appears that there is a method that will allow you to write a newly created profile to disk

  def layout_on_disk    profile_dir = @model ? create_tmp_copy(@model) : Dir.mktmpdir("webdriver-profile")    FileReaper << profile_dir    install_extensions(profile_dir)    delete_lock_files(profile_dir)    delete_extensions_cache(profile_dir)    update_user_prefs_in(profile_dir)    profile_dir  end

Now there isn't much documentation around the Ruby implementation but the Java equivalent of this method has these details

 /**  * Call this to cause the current profile to be written to disk. The profile directory is  * returned. Note that this profile directory is a temporary one and will be deleted when the JVM  * exists (at the latest)  *   * This method should be called immediately before starting to use the profile and should only be  * called once per instance of the {@link org.openqa.selenium.firefox.FirefoxDriver}.  *   * @return The directory containing the profile.  */

To make all this work here is an outline of what has to be done

  1. Set webdriver.reap_profile system property to false. This will prevent clean up of the temporary Firefox profile created.
  2. Create a new Firefox profile, invoke the layoutOnDisk() method to write the profile to disk.
  3. The file path returned from the above step will be stored in a common variable for all tests.
  4. Initiate WebDriver with the newly created profile.

I have not tried to implement this and test it so this may not be the most accurate or workable solution - if it indeed works. It depends on your use case as to why you would want to re-use the same profile across all tests. Hope this helps.