Skip to content

decouple rh vsc ext tester #322

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

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ node_modules
dist
out
scripts
**/*.js
vscode-extension-tester
**/*.js
749 changes: 342 additions & 407 deletions package-lock.json

Large diffs are not rendered by default.

26 changes: 22 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,9 @@
"build": "npm run build:pq-test-result-view",
"copy:i18n": "ts-node scripts/addI18n.ts",
"package": "npm run clean && npm run build && webpack --mode production && npm run copy:i18n",
"compile-tests": "rimraf out && tsc -p . --outDir out",
"compile-tests:page-objects": "npm run build --workspace=vscode-extension-tester-monaco-page-objects",
"compile-tests:locators": "npm run build --workspace=vscode-extension-tester-locators",
"compile-tests": "npm run compile-tests:page-objects && npm run compile-tests:locators && rimraf out && tsc -p . --outDir out",
"watch-tests": "rimraf out && tsc -p . -w --outDir out",
"pretest": "rimraf out && npm run compile-tests && npm run compile && npm run lint",
"audit": "npm audit --omit=dev",
Expand All @@ -377,11 +379,16 @@
},
"devDependencies": {
"@types/chai": "^4.3.12",
"@types/clone-deep": "^4.0.4",
"@types/fs-extra": "^11.0.4",
"@types/glob": "^8.1.0",
"@types/gulp": "^4.0.17",
"@types/got": "^9.6.12",
"@types/js-yaml": "^4.0.9",
"@types/mocha": "^9.1.1",
"@types/node": "^18.19.24",
"@types/sinon": "^10.0.20",
"@types/targz": "^1.0.4",
"@types/vscode": "^1.87.0",
"@typescript-eslint/eslint-plugin": "^5.62.0",
"@typescript-eslint/parser": "^5.62.0",
Expand All @@ -390,27 +397,34 @@
"@vscode/test-electron": "^2.3.9",
"@vscode/vsce": "^2.24.0",
"chai": "^4.4.1",
"clone-deep": "^4.0.1",
"eslint": "^8.57.0",
"eslint-config-prettier": "^8.10.0",
"eslint-plugin-license-header": "^0.4.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-security": "^1.7.1",
"fs-extra": "^11.2.0",
"got": "^14.2.1",
"hpagent": "^1.2.0",
"js-yaml": "^4.1.0",
"glob": "^8.1.0",
"husky": "^8.0.3",
"lint-staged": "^13.3.0",
"mocha": "^9.2.2",
"prettier": "^2.8.8",
"rimraf": "^3.0.2",
"sanitize-filename": "^1.6.3",
"sinon": "^14.0.2",
"ts-essentials": "^9.4.1",
"ts-loader": "^9.5.1",
"ts-node": "^10.9.2",
"tsconfig-paths-webpack-plugin": "^3.5.2",
"typescript": "^4.9.5",
"vinyl-fs": "^4.0.0",
"vscode-extension-tester": "5.10.0",
"vscode-nls-dev": "^4.0.4",
"webpack": "^5.90.3",
"webpack-cli": "^4.10.0"
"webpack-cli": "^4.10.0",
"targz": "^1.0.1"
},
"lint-staged": {
"!(src)/**/*.{ts}": [
Expand All @@ -421,5 +435,9 @@
"hooks": {
"pre-commit": "lint-staged"
}
}
},
"workspaces": [
"vscode-extension-tester/page-objects",
"vscode-extension-tester/locators"
]
}
4 changes: 2 additions & 2 deletions scripts/test-e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import * as path from "path";
import * as os from "os";

import { ExTester } from "vscode-extension-tester";
import { ExTester } from "./tester/exTester";
import { getFirstVsixFileDirectlyBeneathOneDirectory } from "./utils/vsixs";

const theVsixFilePath: string = getFirstVsixFileDirectlyBeneathOneDirectory(process.cwd());
Expand All @@ -19,7 +19,7 @@ async function doE2eTest() {
const extTest = new ExTester(testerResourceFolder);

// Performs all necessary setup: getting VSCode + ChromeDriver into the test instance
await extTest.downloadCode();
await extTest.downloadCode('stable');
await extTest.downloadChromeDriver();

// Install the extension into the test instance of VS Code
Expand Down
195 changes: 195 additions & 0 deletions scripts/tester/browser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
'use strict';

import * as path from 'path';
import * as fs from 'fs-extra';
import { compareVersions } from 'compare-versions';
import { WebDriver, Builder, until, initPageObjects, logging, By, Browser } from 'vscode-extension-tester-monaco-page-objects';
import { Options, ServiceBuilder } from 'selenium-webdriver/chrome';
import { getLocatorsPath } from 'vscode-extension-tester-locators';
import { CodeUtil, ReleaseQuality } from './util/codeUtil';
import { DEFAULT_STORAGE_FOLDER } from './exTester';
import { DriverUtil } from './util/driverUtil';

export class VSBrowser {
static readonly baseVersion = '1.37.0';
static readonly browserName = 'vscode';
private storagePath: string;
private extensionsFolder: string | undefined;
private customSettings: Object;
private _driver!: WebDriver;
private codeVersion: string;
private releaseType: ReleaseQuality;
private logLevel: logging.Level;
private static _instance: VSBrowser;

constructor(codeVersion: string, releaseType: ReleaseQuality, customSettings: Object = {}, logLevel: logging.Level = logging.Level.INFO) {
this.storagePath = process.env.TEST_RESOURCES ? process.env.TEST_RESOURCES : path.resolve(DEFAULT_STORAGE_FOLDER);
this.extensionsFolder = process.env.EXTENSIONS_FOLDER ? process.env.EXTENSIONS_FOLDER : undefined;
this.customSettings = customSettings;
this.codeVersion = codeVersion;
this.releaseType = releaseType;

this.logLevel = logLevel;

VSBrowser._instance = this;
};

/**
* Starts the vscode browser from a given path
* @param codePath path to code binary
*/
async start(codePath: string): Promise<VSBrowser> {
const userSettings = path.join(this.storagePath, 'settings', 'User');
if (fs.existsSync(userSettings)) {
fs.removeSync(path.join(this.storagePath, 'settings'));
}
let defaultSettings = {
"workbench.editor.enablePreview": false,
"workbench.startupEditor": "none",
"window.titleBarStyle": "custom",
"window.commandCenter": false,
"window.dialogStyle": "custom",
"window.restoreFullscreen": true,
"window.newWindowDimensions": "maximized",
"security.workspace.trust.enabled": false,
"files.simpleDialog.enable": true,
"terminal.integrated.copyOnSelection": true
};
if (Object.keys(this.customSettings).length > 0) {
console.log('Detected user defined code settings');
defaultSettings = { ...defaultSettings, ...this.customSettings };
}

fs.mkdirpSync(path.join(userSettings, 'globalStorage'));
await fs.remove(path.join(this.storagePath, 'screenshots'));
fs.writeJSONSync(path.join(userSettings, 'settings.json'), defaultSettings);
console.log(`Writing code settings to ${path.join(userSettings, 'settings.json')}`);

const args = ['--no-sandbox', '--disable-dev-shm-usage', `--user-data-dir=${path.join(this.storagePath, 'settings')}`];

if (this.extensionsFolder) {
args.push(`--extensions-dir=${this.extensionsFolder}`);
}

if (compareVersions(this.codeVersion, '1.39.0') < 0) {
if (process.platform === 'win32') {
fs.copyFileSync(path.resolve(__dirname, '..', '..', 'resources', 'state.vscdb'), path.join(userSettings, 'globalStorage', 'state.vscdb'));
}
args.push(`--extensionDevelopmentPath=${process.cwd()}`);
}

let options = new Options().setChromeBinaryPath(codePath).addArguments(...args) as any;
options['options_'].windowTypes = ['webview'];
options = options as Options;

const prefs = new logging.Preferences();
prefs.setLevel(logging.Type.DRIVER, this.logLevel);
options.setLoggingPrefs(prefs);

const driverBinary = process.platform === 'win32' ? 'chromedriver.exe' : 'chromedriver';
let chromeDriverBinaryPath = path.join(this.storagePath, driverBinary);
if(this.codeVersion >= '1.86.0') {
chromeDriverBinaryPath = path.join(this.storagePath, `chromedriver-${DriverUtil.getChromeDriverPlatform()}`, driverBinary);
}

console.log('Launching browser...');
this._driver = await new Builder()
.setChromeService(new ServiceBuilder(chromeDriverBinaryPath))
.forBrowser(Browser.CHROME)
.setChromeOptions(options)
.build();
VSBrowser._instance = this;

initPageObjects(this.codeVersion, VSBrowser.baseVersion, getLocatorsPath(), this._driver, VSBrowser.browserName);
return this;
}

/**
* Returns a reference to the underlying instance of Webdriver
*/
get driver(): WebDriver {
return this._driver;
}

/**
* Returns the vscode version as string
*/
get version(): string {
return this.codeVersion;
}

/**
* Returns an instance of VSBrowser
*/
static get instance(): VSBrowser {
return VSBrowser._instance;
}

/**
* Waits until parts of the workbench are loaded
*/
async waitForWorkbench(timeout = 30000): Promise<void> {
// Workaround/patch for https://github.com/redhat-developer/vscode-extension-tester/issues/466
try {
await this._driver.wait(until.elementLocated(By.className('monaco-workbench')), timeout, `Workbench was not loaded properly after ${timeout} ms.`);
} catch (err) {
if((err as Error).name === 'WebDriverError') {
await new Promise(res => setTimeout(res, 3000));
} else {
throw err;
}
}
}

/**
* Terminates the webdriver/browser
*/
async quit(): Promise<void> {
const entries = await this._driver.manage().logs().get(logging.Type.DRIVER);
const logFile = path.join(this.storagePath, 'test.log');
const stream = fs.createWriteStream(logFile, { flags: 'w' });
entries.forEach(entry => {
stream.write(`[${new Date(entry.timestamp).toLocaleTimeString()}][${entry.level.name}] ${entry.message}`);
});
stream.end();

console.log('Shutting down the browser');
await this._driver.quit();
}

/**
* Take a screenshot of the browser
* @param name file name of the screenshot without extension
*/
async takeScreenshot(name: string): Promise<void> {
const data = await this._driver.takeScreenshot();
const dir = path.join(this.storagePath, 'screenshots');
fs.mkdirpSync(dir);
fs.writeFileSync(path.join(dir, `${name}.png`), data, 'base64');
}

/**
* Get a screenshots folder path
* @returns string path to the screenshots folder
*/
getScreenshotsDir(): string {
return path.join(this.storagePath, 'screenshots');
}

/**
* Open folder(s) or file(s) in the current instance of vscode.
*
* @param paths path(s) of folder(s)/files(s) to open as varargs
* @returns Promise resolving when all selected resources are opened and the workbench reloads
*/
async openResources(...paths: string[]): Promise<void> {
if (paths.length === 0) {
return;
}

const code = new CodeUtil(this.storagePath, this.releaseType, this.extensionsFolder);
code.open(...paths);
await new Promise(res => setTimeout(res, 3000));
await this.waitForWorkbench();
}
}
Loading