webdriver | | selenium session | Search

This Node.js script uses Selenium WebDriver to create a Chrome browser session, setting environment variables and defining Chrome profile paths based on the operating system. The getClient function creates a new Chrome browser session by setting Chrome profile paths, adding arguments, and returning a promise with the created client instance.

Run example

npm run import -- "selenium client"

selenium client

const { updateOrAddSession } = importer.import("selenium sessions")
const { Builder, Browser, By, Key, until } = require('selenium-webdriver')
const chrome = require('selenium-webdriver/chrome');
const os = require('os')
const path = require('path')
const fs = require('fs')

const APP_SUPPORT = process.env.APP_SUPPORT_DIR || process.env.LOCALAPPDATA 
  || (process.env.HOME ? (os.platform() == 'darwin' ? path.join(process.env.HOME, 'Library/Application Support') : path.join(process.env.HOME, '.config')) : void 0)
  || path.join(process.env.USERPROFILE, 'AppData/Local')
const WIN_PROFILE = path.join(APP_SUPPORT, 'Google/Chrome/User Data/Default')
const DARWIN_PROFILE = path.join(APP_SUPPORT, 'Google/Chrome/Default')
const LINUX_PROFILE = path.join(APP_SUPPORT, 'google-chrome/default')
const CHROME_PROFILE = os.platform() == 'win32' ? WIN_PROFILE : (os.platform() == 'darwin' ? DARWIN_PROFILE : LINUX_PROFILE)

async function getClient() {
  //var client = await remote(webdriverServer);
  //client.setTimeout({ 'implicit': 15000 })
  //client.setTimeout({ 'pageLoad': 15000 })
  //let windows = await client.getWindowHandles();
  let builder = await new Builder().forBrowser(Browser.CHROME)
  let options = new chrome.Options()
  options.port = 4444

  // this ensures the profile stays the same between runs, default is randomly generate a new profile every time
  if(fs.existsSync(CHROME_PROFILE)) {
    console.log('starting client', path.join(path.dirname(CHROME_PROFILE), 'not-Default'))
    options.addArguments('--user-data-dir=' + path.join(path.dirname(CHROME_PROFILE), 'not-Default'))
  } else {
    console.log('starting client', '/tmp/profile-1')
    options.addArguments('--user-data-dir=/tmp/profile-1')
  }

  options.addArguments('--no-sandbox')
  options.addArguments('--disable-session-crashed-bubble')
  options.addArguments('--disable-infobars')
  options.addArguments('--new-window')
  options.addArguments('--disable-geolocation')
  options.addArguments('--disable-notifications')
  options.addArguments('--show-saved-copy')
  options.addArguments('--silent-debugger-extension-api')
  options.addArguments('--disable-blink-features=AutomationControlled')
  options.addArguments('--port=4444')

  //options.setUserPreferences({'download.default_directory': });
  options.setUserPreferences({
    'profile.default_content_setting_values.notifications': 2,
    'exited_cleanly': true,
    'exit_type': 'None'
  })

  builder.setChromeOptions(options)
  // builder.withCapabilities(options.toCapabilities())
  let driver = builder.build()
  
  await driver.manage().setTimeouts({ pageLoad: 10000 })

  // keep track of session in case it can be reattached later
  await updateOrAddSession((await driver.getSession()).getId())
  //let sessions = await getSessions(driver, true)

  let session = await driver.getSession()
  let original = session.getId()
  //for(let i = 0; i < sessions.length; i++) {
  //  if(sessions[i][1] != original) {
  //    await closeAllWindows(driver, sessions[i])
  //  }
  //}
  session.id_ = original
  return driver
}

module.exports = getClient

What the code could have been:

const { updateOrAddSession } = require('./selenium-sessions');
const { Builder, Browser, By, Key, until } = require('selenium-webdriver');
const chrome = require('selenium-webdriver/chrome');
const os = require('os');
const path = require('path');
const fs = require('fs');

const APP_SUPPORT_DIR = getSupportDir();
const CHROME_PROFILE =
  os.platform() === 'win32'
   ? path.join(APP_SUPPORT_DIR, 'Google/Chrome/User Data/Default')
    : (os.platform() === 'darwin'
       ? path.join(APP_SUPPORT_DIR, 'Google/Chrome/Default')
        : path.join(APP_SUPPORT_DIR, 'google-chrome/default'));

async function getClient() {
  // Create a new instance of the Chrome driver
  const builder = new Builder().forBrowser(Browser.CHROME);
  const chromeOptions = new chrome.Options();

  // Set up Chrome options
  chromeOptions
   .addArguments('--no-sandbox')
   .addArguments('--disable-session-crashed-bubble')
   .addArguments('--disable-infobars')
   .addArguments('--new-window')
   .addArguments('--disable-geolocation')
   .addArguments('--disable-notifications')
   .addArguments('--show-saved-copy')
   .addArguments('--silent-debugger-extension-api')
   .addArguments('--disable-blink-features=AutomationControlled')
   .addArguments('--port=4444');

  // Use the existing profile if it exists
  if (fs.existsSync(CHROME_PROFILE)) {
    console.log('Using existing profile:', CHROME_PROFILE);
    chromeOptions.addArguments('--user-data-dir=' + path.join(path.dirname(CHROME_PROFILE), 'not-Default'));
  } else {
    console.log('Creating new profile at:', '/tmp/profile-1');
    chromeOptions.addArguments('--user-data-dir=/tmp/profile-1');
  }

  // Set Chrome user preferences
  chromeOptions.setUserPreferences({
    'profile.default_content_setting_values.notifications': 2,
    'exited_cleanly': true,
    'exit_type': 'None',
  });

  // Set up the driver
  const driver = builder.setChromeOptions(chromeOptions).build();

  // Set up timeouts
  await driver.manage().setTimeouts({ pageLoad: 10000 });

  // Keep track of the session
  await updateOrAddSession((await driver.getSession()).getId());

  return driver;
}

// Helper function to get the application support directory
function getSupportDir() {
  const appSupportDir =
    process.env.APP_SUPPORT_DIR ||
    process.env.LOCALAPPDATA ||
    (process.env.HOME
     ? os.platform() === 'darwin'
       ? path.join(process.env.HOME, 'Library/Application Support')
        : path.join(process.env.HOME, '.config')
      : void 0) ||
    path.join(process.env.USERPROFILE, 'AppData/Local');

  return appSupportDir;
}

module.exports = getClient;

Code Breakdown

This code is a Node.js script that utilizes the Selenium WebDriver to create a Chrome browser session. Here's a simplified explanation of the code:

Importing Dependencies

The script starts by importing necessary dependencies:

Setting Environment Variables

The script sets environment variables for the application support directory:

Defining Chrome Profile Paths

Based on the operating system, the script defines paths to the Chrome profile:

Client Function

The getClient function creates a new Chrome browser session using Selenium WebDriver. Here's a breakdown of the function:

  1. Creates a new Builder instance for the Chrome browser.
  2. Sets the Chrome profile path using chrome.Options.
  3. If the Chrome profile exists, it adds an argument to use the profile directory (--user-data-dir).
  4. Adds various Chrome arguments to bypass sandboxing, disable notifications, and more.
  5. Returns a promise with the created client instance.

The function uses asynchronous code to create the client instance, which can be consumed by other parts of the script.

Unused Code

The script contains some unused code:

These lines seem to be leftovers from a previous implementation or testing.