Skip to content

[🚫 Bug] Getting error SessionNotCreatedError: session not created: probably user data directory is already in use, please specify a unique value for --user-data-dir argument, or don't use --user-data-dir when browser #1840

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
peternhale opened this issue Apr 10, 2025 · 2 comments
Labels
bug Something isn't working question Further information is requested
Milestone

Comments

@peternhale
Copy link

Describe the bug

Getitng error with starting tests on Ubuntu/node 22

SessionNotCreatedError: session not created: probably user data directory is already in use, please specify a unique value for --user-data-dir argument, or don't use --user-data-dir

I am create a framework around vscode-extension-tester to simplify the work my team needs to do to setup a multi-extension test run.

I am setting these vars in GH action so I have predictable locations to archive artifacts generated during the test

TEST_RESOURCES: test-resources-${{ github.run_id }}
EXTENSIONS_FOLDER: extensions-${{ github.run_id }}

The directories are created in GH actions just before the npm run test is run.

I have extended the ExTester to allow for extension installation, etc.
constructor

  constructor(
    testConfig?: Partial<TestConfig>,
    private spec?: string | string[] | undefined
  ) {
    // Create config with defaults and overrides
    const config = createDefaultTestConfig(testConfig);

    // Validate config and set defaults for missing values
    validateTestConfig(config);

    // Set up the VS Code download location as a sibling directory to workspace
    const workspaceDir = path.dirname(config.testResources);
    const vscodeDownloadDir = path.join(workspaceDir, 'vscode');
    super(config.extensionsFolder, ReleaseQuality.Stable, normalizePath(vscodeDownloadDir));
    this.testConfig = config;
  }

I start the tests via

    const useExistingProject = EnvironmentSettings.getInstance().useExistingProject;
    const resources = useExistingProject ? [useExistingProject] : [];
    return super.runTests(this.spec || EnvironmentSettings.getInstance().specFiles, { resources });

I see the following in the logs

Created VS Code directory: vscode
Downloading VS Code: 1.99.2 / stable
Downloading VS Code from: https://update.code.visualstudio.com/latest/linux-x64/stable
progress: 0/163 (0%)
progress: 148557070/148557070 (100%)
Downloaded VS Code into /home/runner/work/<redacted>/extensions-14390011958/stable.tar.gz
Unpacking VS Code into /home/runner/work/<redacted>/extensions-14390011958
Success!
Downloading ChromeDriver 132.0.6834.159 from: https://storage.googleapis.com/chrome-for-testing-public/132.0.6834.159/linux64/chromedriver-linux64.zip
progress: 0/9270115 (0%)
progress: 9270115/9270115 (100%)
Unpacking ChromeDriver 132.0.6834.159 into /home/runner/work/<redacted>/extensions-14390011958
Success!
No vsix files were found in dir /home/runner/work/<redacted>/extensions-14390011958, skipping extension installation
Checking if org with matching alias and username is already authenticated...
running CLI command org:list --json
Command finished with exit code 0
No existing authenticated org found: Error: matching devHub alias 'vscodeOrg' and devHub user name '***' was not found.
Please consult README.md and make sure DEV_HUB_ALIAS_NAME and DEV_HUB_USER_NAME are set correctly.
Authenticating using SFDX_AUTH_URL...
running CLI command org:login:sfdx-url -d -f authFile.txt
Command finished with exit code 0
running CLI command alias:set vscodeOrg=***
Command finished with exit code 0
Loading mocha configuration from /home/runner/work/<redacted>/.mocharc.json


Writing code settings to /home/runner/work/<redacted>/extensions-14390011958/settings/User/settings.json
Launching browser...
  1) "before all" hook in "{root}"
  2) "after all" hook in "{root}"

  0 passing (2s)
  2 failing

  1) "before all" hook in "{root}":
     SessionNotCreatedError: session not created: probably user data directory is already in use, please specify a unique value for --user-data-dir argument, or don't use --user-data-dir
      at Object.throwDecodedError (node_modules/selenium-webdriver/lib/error.js:521:15)
      at parseHttpResponse (node_modules/selenium-webdriver/lib/http.js:524:13)
      at Executor.execute (node_modules/selenium-webdriver/lib/http.js:456:28)
      at process.processTicksAndRejections (node:internal/process/task_queues:105:5)

Steps to reproduce

See above

Logs

Created VS Code directory: vscode
Downloading VS Code: 1.99.2 / stable
Downloading VS Code from: https://update.code.visualstudio.com/latest/linux-x64/stable
progress: 0/163 (0%)
progress: 148557070/148557070 (100%)
Downloaded VS Code into /home/runner/work/<redacted>/extensions-14390011958/stable.tar.gz
Unpacking VS Code into /home/runner/work/<redacted>/extensions-14390011958
Success!
Downloading ChromeDriver 132.0.6834.159 from: https://storage.googleapis.com/chrome-for-testing-public/132.0.6834.159/linux64/chromedriver-linux64.zip
progress: 0/9270115 (0%)
progress: 9270115/9270115 (100%)
Unpacking ChromeDriver 132.0.6834.159 into /home/runner/work/<redacted>/extensions-14390011958
Success!
No vsix files were found in dir /home/runner/work/<redacted>/extensions-14390011958, skipping extension installation
Checking if org with matching alias and username is already authenticated...
running CLI command org:list --json
Command finished with exit code 0
No existing authenticated org found: Error: matching devHub alias 'vscodeOrg' and devHub user name '***' was not found.
Please consult README.md and make sure DEV_HUB_ALIAS_NAME and DEV_HUB_USER_NAME are set correctly.
Authenticating using SFDX_AUTH_URL...
running CLI command org:login:sfdx-url -d -f authFile.txt
Command finished with exit code 0
running CLI command alias:set vscodeOrg=***
Command finished with exit code 0
Loading mocha configuration from /home/runner/work/<redacted>/.mocharc.json


Writing code settings to /home/runner/work/<redacted>/extensions-14390011958/settings/User/settings.json
Launching browser...
  1) "before all" hook in "{root}"
  2) "after all" hook in "{root}"

  0 passing (2s)
  2 failing

  1) "before all" hook in "{root}":
     SessionNotCreatedError: session not created: probably user data directory is already in use, please specify a unique value for --user-data-dir argument, or don't use --user-data-dir
      at Object.throwDecodedError (node_modules/selenium-webdriver/lib/error.js:521:15)
      at parseHttpResponse (node_modules/selenium-webdriver/lib/http.js:524:13)
      at Executor.execute (node_modules/selenium-webdriver/lib/http.js:456:28)
      at process.processTicksAndRejections (node:internal/process/task_queues:105:5)

Operating System

ubuntu-latest

Visual Studio Code

latest (1.98.*)

vscode-extension-tester

8.8.1

NodeJS

22

npm

No response

@peternhale peternhale added bug Something isn't working new-issue New issue which was not discussed yet labels Apr 10, 2025
@djelinek
Copy link
Collaborator

Hello, hmmm I will need to better understand how the ExTester API is used..

I can see you are using runTests - return super.runTests(this.spec || EnvironmentSettings.getInstance().specFiles, { resources });

which other steps are you using before? setupRequirements , installVsix , ... ? and potentially how are you using them?

when using API you need to double check and be careful when redefining default extensions installation dir. If so, then each method from API needs to point to the same appropriate extensions dir (except get-vscode/chromedriver)

@djelinek djelinek added question Further information is requested and removed new-issue New issue which was not discussed yet labels Apr 14, 2025
@djelinek djelinek moved this from New to Backlog in ExTester Apr 14, 2025
@djelinek djelinek added this to the Backlog milestone Apr 14, 2025
@peternhale
Copy link
Author

Hi @djelinek the source below is extending ExTester. My latest attempt in CI/CD is not setting EXTENSIONS_FOLDER or TEST_RESOURCES to avoid potential conflicts.

Most recent error from CI/CI

Writing code settings to /tmp/test-resources/settings/User/settings.json
Launching browser...
  1) "before all" hook in "{root}"
  2) "after all" hook in "{root}"

  0 passing (2s)
  2 failing

  1) "before all" hook in "{root}":
     SessionNotCreatedError: session not created: probably user data directory is already in use, please specify a unique value for --user-data-dir argument, or don't use --user-data-dir
      at Object.throwDecodedError (node_modules/selenium-webdriver/lib/error.js:521:15)
      at parseHttpResponse (node_modules/selenium-webdriver/lib/http.js:524:13)
      at Executor.execute (node_modules/selenium-webdriver/lib/http.js:456:28)
      at process.processTicksAndRejections (node:internal/process/task_queues:105:5)

  2) "after all" hook in "{root}":
     TypeError: Cannot read properties of undefined (reading 'manage')
      at VSBrowser.quit (node_modules/vscode-extension-tester/out/browser.js:184:44)
      at Context.<anonymous> (node_modules/vscode-extension-tester/out/suite/runner.js:136:31)
      at process.processImmediate (node:internal/timers:491:21)

Source extending ExTester

import { ExTester } from 'vscode-extension-tester';
import { EnvironmentSettings } from './environmentSettings';
import path from 'path';
import fs from 'fs/promises';
import { extensions } from './testing/extensionUtils';
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import { ReleaseQuality } from 'vscode-extension-tester/out/util/codeUtil';
import { expect } from 'chai';
import { log } from 'console';
import { orgLoginSfdxUrl, setAlias } from './system-operations/cliCommands';
import { getVsixFilesFromDir } from './system-operations';
import { TestConfig } from './core/types';
import { createDefaultTestConfig, validateTestConfig, normalizePath } from './core/helpers';
import { verifyAliasAndUserName } from './salesforce-components/authorization';

class TestSetupAndRunner extends ExTester {
  protected static _exTestor: TestSetupAndRunner;
  private testConfig: TestConfig;

  constructor(
    testConfig?: Partial<TestConfig>,
    private spec?: string | string[] | undefined
  ) {
    // Create config with defaults and overrides
    const config = createDefaultTestConfig(testConfig);

    // Validate config and set defaults for missing values
    validateTestConfig(config);

    super(undefined, ReleaseQuality.Stable);
    this.testConfig = config;
  }

  /**
   * Helper method to log important test information using standard terminology
   */
  private logTestEnvironment(): void {
    log(`Setting up test environment with:`);
    log(`- Test Resources: ${this.testConfig.testResources}`);
    log(`- Extensions Folder: ${this.testConfig.extensionsFolder}`);
    log(`- VS Code Version: ${this.testConfig.codeVersion}`);

    // Log Chrome driver arguments if available
    const chromeDriverArgs = EnvironmentSettings.getInstance().chromeDriverArgs;
    if (chromeDriverArgs) {
      log(`- ChromeDriver Arguments: ${chromeDriverArgs}`);
    }
  }

  public async setup(): Promise<void> {
    // Log the test environment configuration
    this.logTestEnvironment();

    await this.downloadCode(this.testConfig.codeVersion);
    await this.downloadChromeDriver(this.testConfig.codeVersion);

    try {
      await this.installExtensions();
    } catch (error: unknown) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      log(`Warning: Failed to install extensions: ${errorMessage}. Continuing setup.`);
    }
    await this.setupAndAuthorizeOrg();
  }

  public async runTests(): Promise<number> {
    const useExistingProject = EnvironmentSettings.getInstance().useExistingProject;
    const resources = useExistingProject ? [useExistingProject] : [];
    return super.runTests(this.spec || EnvironmentSettings.getInstance().specFiles, { resources });
  }
  public async installExtension(extension: string): Promise<void> {
    log(`SetUp - Started Install extension ${path.basename(extension)}`);
    await this.installVsix({ useYarn: false, vsixFile: extension });
  }

  public async installExtensions(excludeExtensions: string[] = []): Promise<void> {
    const vsixToInstallDir = this.testConfig.vsixToInstallDir || EnvironmentSettings.getInstance().vsixToInstallDir;

    if (!vsixToInstallDir) {
      log(`No VSIX_TO_INSTALL directory specified, the tests will run without installing any extensions`);
      return;
    }

    // Check if the directory exists
    try {
      await fs.access(vsixToInstallDir);
    } catch (error) {
      throw new Error(`VSIX_TO_INSTALL directory does not exist or is not accessible: ${vsixToInstallDir}`);
    }

    // Check for already installed extensions
    const extensionPattern = /^(?<publisher>.+?)\.(?<extensionId>.+?)-(?<version>\d+\.\d+\.\d+)(?:\.\d+)*$/;
    const extensionsDirEntries = (await fs.readdir(vsixToInstallDir)).map(entry =>
      path.resolve(normalizePath(path.join(vsixToInstallDir, entry)))
    );
    const foundInstalledExtensions = await Promise.all(
      extensionsDirEntries
        .filter(async entry => {
          try {
            const stats = await fs.stat(entry);
            return stats.isDirectory();
          } catch (e) {
            log(`stat failed for file ${entry}`);
            return false;
          }
        })
        .map(entry => {
          const match = path.basename(entry).match(extensionPattern);
          if (match?.groups) {
            return {
              publisher: match.groups.publisher,
              extensionId: match.groups.extensionId,
              version: match.groups.version,
              path: entry
            };
          }
          return null;
        })
        .filter(Boolean)
        .filter(ext =>
          extensions.find(refExt => {
            return refExt.extensionId === ext?.extensionId;
          })
        )
    );

    if (
      foundInstalledExtensions.length > 0 &&
      foundInstalledExtensions.every(ext => extensions.find(refExt => refExt.extensionId === ext?.extensionId))
    ) {
      log(`Found the following pre-installed extensions in dir ${vsixToInstallDir}, skipping installation of vsix`);
      foundInstalledExtensions.forEach(ext => {
        log(`Extension ${ext?.extensionId} version ${ext?.version}`);
      });
      return;
    }

    const extensionsVsixs = getVsixFilesFromDir(vsixToInstallDir);
    if (extensionsVsixs.length === 0) {
      log(`No vsix files were found in dir ${vsixToInstallDir}, skipping extension installation`);
      return; // Skip installation instead of throwing an error
    }

    const mergeExcluded = Array.from(
      new Set([
        ...excludeExtensions,
        ...extensions.filter(ext => ext.shouldInstall === 'never').map(ext => ext.extensionId)
      ])
    );

    // Refactored part to use the extensions array
    extensionsVsixs.forEach(vsix => {
      const match = path.basename(vsix).match(/^(?<extension>.*?)(-(?<version>\d+\.\d+\.\d+))?\.vsix$/);
      if (match?.groups) {
        const { extension, version } = match.groups;
        const foundExtension = extensions.find(e => e.extensionId === extension);
        if (foundExtension) {
          foundExtension.vsixPath = vsix;
          // assign 'never' to this extension if its id is included in excluedExtensions
          foundExtension.shouldInstall = mergeExcluded.includes(foundExtension.extensionId) ? 'never' : 'always';
          // if not installing, don't verify, otherwise use default value
          foundExtension.shouldVerifyActivation =
            foundExtension.shouldInstall === 'never' ? false : foundExtension.shouldVerifyActivation;
          log(`SetUp - Found extension ${extension} version ${version} with vsixPath ${foundExtension.vsixPath}`);
        }
      }
    });

    // Iterate over the extensions array to install extensions
    for (const extensionObj of extensions.filter(ext => ext.vsixPath !== '' && ext.shouldInstall !== 'never')) {
      await this.installExtension(extensionObj.vsixPath);
    }
  }

  public async setupAndAuthorizeOrg() {
    const environmentSettings = EnvironmentSettings.getInstance();
    const devHubUserName = environmentSettings.devHubUserName;
    const devHubAliasName = environmentSettings.devHubAliasName;
    const SFDX_AUTH_URL = environmentSettings.sfdxAuthUrl;

    try {
      // First try to verify if the org with alias and username exists
      log('Checking if org with matching alias and username is already authenticated...');
      await verifyAliasAndUserName();
      log(`Org with alias ${devHubAliasName} and username ${devHubUserName} is already authenticated`);
      return;
    } catch (error) {
      // If verification fails, continue with SFDX_AUTH_URL
      const errorMessage = error instanceof Error ? error.message : String(error);
      log(`No existing authenticated org found: ${errorMessage}`);

      // If no SFDX_AUTH_URL is provided, rethrow the error
      if (!SFDX_AUTH_URL) {
        throw new Error('No SFDX_AUTH_URL provided and no existing authentication found. Unable to authorize org.');
      }
    }

    // The verifyAliasAndUserName function already checks that both alias and username are set,
    // so at this point we know they are defined (or we would have thrown earlier).
    // TypeScript doesn't know this though, so we'll add the non-null assertion
    if (!devHubUserName || !devHubAliasName) {
      throw new Error(
        'DevHub username or alias name is not set. This should not happen as verifyAliasAndUserName should have caught this.'
      );
    }

    // At this point, neither alias nor username matched an existing org,
    // and we have an SFDX_AUTH_URL to use
    log('Authenticating using SFDX_AUTH_URL...');
    const sfdxAuthUrl = String(SFDX_AUTH_URL);
    const authFilePath = 'authFile.txt';

    // Create and write the SFDX Auth URL in a text file
    await fs.writeFile(authFilePath, sfdxAuthUrl);

    // Step 1: Authorize to Testing Org
    const authorizeOrg = await orgLoginSfdxUrl(authFilePath);
    expect(authorizeOrg.stdout).to.contain(`Successfully authorized ${devHubUserName}`);

    // Step 2: Set Alias for the Org
    const setAliasResult = await setAlias(devHubAliasName, devHubUserName);
    expect(setAliasResult.stdout).to.contain(devHubAliasName);
    expect(setAliasResult.stdout).to.contain(devHubUserName);
    expect(setAliasResult.stdout).to.contain('true');
  }

  async downloadCode(version = 'latest'): Promise<void> {
    await super.downloadCode(version);
  }

  static get exTester(): TestSetupAndRunner {
    if (TestSetupAndRunner.exTester) {
      return TestSetupAndRunner._exTestor;
    }
    TestSetupAndRunner._exTestor = new TestSetupAndRunner();
    return TestSetupAndRunner._exTestor;
  }
}

// Parse command-line arguments
const argv = yargs(hideBin(process.argv))
  .option('spec', {
    alias: 's',
    type: 'string',
    description: 'Glob pattern for test files or list of test files',
    demandOption: false,
    array: true
  })
  .help().argv as {
  spec: string | string[] | undefined;
};

// Create test config from command line arguments
const testConfig: Partial<TestConfig> = {};

const testSetupAnRunner = new TestSetupAndRunner(testConfig, argv.spec);
async function run() {
  try {
    await testSetupAnRunner.setup();
    const result = await testSetupAnRunner.runTests();
    console.log(result);
    process.exit(result);
  } catch (error) {
    console.error(error);
    process.exit(1);
  }
}

void run();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working question Further information is requested
Projects
Status: Backlog
Development

No branches or pull requests

2 participants