From aacc77af60b0bafdff1a9200cc30d16183bfa7b6 Mon Sep 17 00:00:00 2001 From: Tami Takamiya Date: Thu, 8 Feb 2024 21:42:50 -0500 Subject: [PATCH 1/7] Reenable extenstionDevelopmentPath flag --- src/browser.ts | 6 +++++- src/cli.ts | 3 ++- src/extester.ts | 4 ++-- src/util/codeUtil.ts | 7 ++++++- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/browser.ts b/src/browser.ts index 85e580d1e..ffc72e039 100644 --- a/src/browser.ts +++ b/src/browser.ts @@ -15,6 +15,7 @@ export class VSBrowser { static readonly browserName = 'vscode'; private storagePath: string; private extensionsFolder: string | undefined; + private extensionDevelopmentPath: string | undefined; private customSettings: Object; private _driver!: WebDriver; private codeVersion: string; @@ -25,6 +26,7 @@ export class 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.extensionDevelopmentPath = process.env.EXTENSION_DEV_PATH ? process.env.EXTENSION_DEV_PATH : undefined; this.customSettings = customSettings; this.codeVersion = codeVersion; this.releaseType = releaseType; @@ -76,6 +78,8 @@ export class VSBrowser { fs.copyFileSync(path.resolve(__dirname, '..', '..', 'resources', 'state.vscdb'), path.join(userSettings, 'globalStorage', 'state.vscdb')); } args.push(`--extensionDevelopmentPath=${process.cwd()}`); + } else if(this.extensionDevelopmentPath) { + args.push(`--extensionDevelopmentPath=${this.extensionDevelopmentPath}`); } let options = new Options().setChromeBinaryPath(codePath).addArguments(...args) as any; @@ -187,7 +191,7 @@ export class VSBrowser { return; } - const code = new CodeUtil(this.storagePath, this.releaseType, this.extensionsFolder); + const code = new CodeUtil(this.storagePath, this.releaseType, this.extensionsFolder, this.extensionDevelopmentPath); code.open(...paths); await new Promise(res => setTimeout(res, 3000)); await this.waitForWorkbench(); diff --git a/src/cli.ts b/src/cli.ts index 94cb58229..211b9c3eb 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -80,9 +80,10 @@ program.command('run-tests ') .option('-m, --mocha_config ', 'Path to Mocha configuration file') .option('-l, --log_level ', 'Log messages from webdriver with a given level', 'Info') .option('-f, --offline', 'Attempt to run without internet connection, make sure to have all requirements downloaded', false) + .option('-d, --extension_development_path ', 'VSCode will use the unpackaged extension source from this directory') .option('-r, --open_resource ', 'Open resources in VS Code. Multiple files and folders can be specified.') .action(withErrors(async (testFiles, cmd) => { - const extest = new ExTester(cmd.storage, codeStream(cmd.type), cmd.extensions_dir); + const extest = new ExTester(cmd.storage, codeStream(cmd.type), cmd.extensions_dir, cmd.extension_development_path); await extest.runTests(testFiles, {vscodeVersion: cmd.code_version, settings: cmd.code_settings, cleanup: cmd.uninstall_extension, config: cmd.mocha_config, logLevel: cmd.log_level, offline: cmd.offline, resources: cmd.open_resource ?? []}); })); diff --git a/src/extester.ts b/src/extester.ts index 20206d701..d8af5c8ab 100644 --- a/src/extester.ts +++ b/src/extester.ts @@ -44,8 +44,8 @@ export class ExTester { private code: CodeUtil; private chrome: DriverUtil; - constructor(storageFolder: string = DEFAULT_STORAGE_FOLDER, releaseType: ReleaseQuality = ReleaseQuality.Stable, extensionsDir?: string) { - this.code = new CodeUtil(storageFolder, releaseType, extensionsDir); + constructor(storageFolder: string = DEFAULT_STORAGE_FOLDER, releaseType: ReleaseQuality = ReleaseQuality.Stable, extensionsDir?: string, extensionDevPath?: string) { + this.code = new CodeUtil(storageFolder, releaseType, extensionsDir, extensionDevPath); this.chrome = new DriverUtil(storageFolder); if (process.versions.node.slice(0, 2) > NODEJS_VERSION_MAX) { diff --git a/src/util/codeUtil.ts b/src/util/codeUtil.ts index 2d8184766..7cd1aaa2a 100644 --- a/src/util/codeUtil.ts +++ b/src/util/codeUtil.ts @@ -28,6 +28,8 @@ export interface RunOptions { logLevel?: logging.Level; /** try to perform all setup without internet connection, needs all requirements pre-downloaded manually */ offline?: boolean; + /** path to unbundled extension sources */ + extensionDevelopmentPath?: string; /** list of resources to be opened by VS Code */ resources: string[]; } @@ -55,17 +57,19 @@ export class CodeUtil { private cliEnv!: string; private availableVersions: string[]; private extensionsFolder: string | undefined; + private extensionDevelopmentPath: string | undefined; /** * Create an instance of code handler * @param folder Path to folder where all the artifacts will be stored. * @param extensionsFolder Path to use as extensions directory by VS Code */ - constructor(folder: string = DEFAULT_STORAGE_FOLDER, type: ReleaseQuality = ReleaseQuality.Stable, extensionsFolder?: string) { + constructor(folder: string = DEFAULT_STORAGE_FOLDER, type: ReleaseQuality = ReleaseQuality.Stable, extensionsFolder?: string, extensionDevelopmentPath?: string) { this.availableVersions = []; this.downloadPlatform = this.getPlatform(); this.downloadFolder = path.resolve(folder); this.extensionsFolder = extensionsFolder ? path.resolve(extensionsFolder) : undefined; + this.extensionDevelopmentPath = extensionDevelopmentPath ? path.resolve(extensionDevelopmentPath) : undefined; this.releaseType = type; if (type === ReleaseQuality.Stable) { @@ -257,6 +261,7 @@ export class CodeUtil { process.env = finalEnv; process.env.TEST_RESOURCES = this.downloadFolder; process.env.EXTENSIONS_FOLDER = this.extensionsFolder; + process.env.EXTENSION_DEV_PATH = this.extensionDevelopmentPath; const runner = new VSRunner(this.executablePath, literalVersion, this.parseSettings(runOptions.settings ?? DEFAULT_RUN_OPTIONS.settings), runOptions.cleanup, this.releaseType, runOptions.config); return await runner.runTests(testFilesPattern, this, runOptions.logLevel, runOptions.resources); } From 46f3f257d1a49b3f325d814e8a5b01ffc82cbfdf Mon Sep 17 00:00:00 2001 From: Tami Takamiya Date: Sat, 10 Feb 2024 00:42:01 -0500 Subject: [PATCH 2/7] Generate code coverage report on test-project --- .gitignore | 1 + package.json | 3 ++- src/cli.ts | 6 ++++-- src/extester.ts | 6 +++++- src/util/codeUtil.ts | 7 +++++++ test/test-project/package.json | 4 +++- 6 files changed, 22 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 0bb05d1b8..2099076ac 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ resources/api-handler.vsix .npmrc *.tgz test/test-project/package-lock.json +test/test-project/coverage diff --git a/package.json b/package.json index 42851c75b..93e1b9df5 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,8 @@ "prebuild": "npm run build --workspaces", "build": "rimraf out/ && tsc && chmod a+x ./out/cli.js", "pretest": "npm run build && npm install --prefix test/test-project", - "test": "npm run ui-test --prefix test/test-project" + "test": "npm run ui-test --prefix test/test-project", + "coverage": "npm run build && npm run pretest && cd test/test-project && npm run ui-coverage" }, "repository": { "type": "git", diff --git a/src/cli.ts b/src/cli.ts index 211b9c3eb..30603165f 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -64,8 +64,9 @@ program.command('setup-tests') .option('-t, --type ', 'Type of VS Code release (stable/insider)') .option('-y, --yarn', 'Use yarn to build the extension via vsce instead of npm', false) .option('-i, --install_dependencies', 'Automatically install extensions your extension depends on', false) + .option('-d, --extension_development_path ', 'VSCode will use the unpackaged extension source from this directory') .action(withErrors(async (cmd) => { - const extest = new ExTester(cmd.storage, codeStream(cmd.type), cmd.extensions_dir); + const extest = new ExTester(cmd.storage, codeStream(cmd.type), cmd.extensions_dir, cmd.extension_development_path); await extest.setupRequirements({vscodeVersion: cmd.code_version, useYarn: cmd.yarn, installDependencies: cmd.install_dependencies}); })); @@ -100,9 +101,10 @@ program.command('setup-and-run ') .option('-i, --install_dependencies', 'Automatically install extensions your extension depends on', false) .option('-l, --log_level ', 'Log messages from webdriver with a given level', 'Info') .option('-f, --offline', 'Attempt to run without internet connection, make sure to have all requirements downloaded', false) + .option('-d, --extension_development_path ', 'VSCode will use the unpackaged extension source from this directory') .option('-r, --open_resource ', 'Open resources in VS Code. Multiple files and folders can be specified.') .action(withErrors(async (testFiles, cmd) => { - const extest = new ExTester(cmd.storage, codeStream(cmd.type), cmd.extensions_dir); + const extest = new ExTester(cmd.storage, codeStream(cmd.type), cmd.extensions_dir, cmd.extension_development_path); await extest.setupAndRunTests(testFiles, cmd.code_version, {useYarn: cmd.yarn, installDependencies: cmd.install_dependencies}, {settings: cmd.code_settings, cleanup: cmd.uninstall_extension, config: cmd.mocha_config, logLevel: cmd.log_level, resources: cmd.open_resource ?? []}); })); diff --git a/src/extester.ts b/src/extester.ts index d8af5c8ab..ddecc6400 100644 --- a/src/extester.ts +++ b/src/extester.ts @@ -133,7 +133,11 @@ export class ExTester { console.log(`Attempting with ChromeDriver ${actualChromeVersion} anyway. Tests may experience issues due to version mismatch.`); } } - await this.installVsix({useYarn}); + if (!this.code.extensionDevPath) { + await this.code.packageExtension(useYarn); + } else { + await this.installVsix({useYarn}); + } if (installDependencies && !offline) { this.code.installDependencies(); } diff --git a/src/util/codeUtil.ts b/src/util/codeUtil.ts index 7cd1aaa2a..b42902745 100644 --- a/src/util/codeUtil.ts +++ b/src/util/codeUtil.ts @@ -341,6 +341,13 @@ export class CodeUtil { return this.codeFolder; } + /** + * Getter for extension development path + */ + get extensionDevPath() { + return this.extensionDevelopmentPath; + } + /** * Check if given version is available in the given stream */ diff --git a/test/test-project/package.json b/test/test-project/package.json index 773fdbc58..6b99ec46a 100644 --- a/test/test-project/package.json +++ b/test/test-project/package.json @@ -170,7 +170,8 @@ "lint": "eslint src --ext .ts", "watch": "tsc -watch -p ./", "cb-init": "echo hello_ExTester | clipboard", - "ui-test": "npm run cb-init && extest setup-and-run './out/src/test/cli/order-3-test.js' './out/src/test/cli/order-2-test.js' './out/src/test/cli/order-1-test.js' './out/src/test/**/*-test.js' './out/src/test/system/clipboard.test.js' -u -i -r . -e ./test-extensions" + "ui-test": "npm run cb-init && extest setup-and-run './out/src/test/cli/order-3-test.js' './out/src/test/cli/order-2-test.js' './out/src/test/cli/order-1-test.js' './out/src/test/**/*-test.js' './out/src/test/system/clipboard.test.js' -u -i -r . -e ./test-extensions", + "ui-coverage": "npm run cb-init && npx c8 -r text -r html extest setup-and-run './out/src/test/cli/order-3-test.js' './out/src/test/cli/order-2-test.js' './out/src/test/cli/order-1-test.js' './out/src/test/**/*-test.js' './out/src/test/system/clipboard.test.js' -u -i -r . -e ./test-extensions -d ." }, "devDependencies": { "@types/chai": "^4.3.14", @@ -178,6 +179,7 @@ "@types/vscode": "^1.82.0", "@typescript-eslint/eslint-plugin": "^7.3.1", "@typescript-eslint/parser": "^7.3.1", + "c8": "^9.1.0", "chai": "^4.4.1", "clipboard-cli": "^4.0.0", "clipboardy": "^4.0.0", From 321b92df8cc5d40a3eeda60a641d9dc62f3f25f8 Mon Sep 17 00:00:00 2001 From: Tami Takamiya Date: Mon, 25 Mar 2024 16:40:34 -0400 Subject: [PATCH 3/7] use npm --prefix flag --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 93e1b9df5..efa467769 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "build": "rimraf out/ && tsc && chmod a+x ./out/cli.js", "pretest": "npm run build && npm install --prefix test/test-project", "test": "npm run ui-test --prefix test/test-project", - "coverage": "npm run build && npm run pretest && cd test/test-project && npm run ui-coverage" + "coverage": "npm run build && npm run pretest && npm run ui-coverage --prefix test/test-project" }, "repository": { "type": "git", From 8b03b72519f7cb23535048607843920e3a46c704 Mon Sep 17 00:00:00 2001 From: Tami Takamiya Date: Thu, 8 Feb 2024 21:42:50 -0500 Subject: [PATCH 4/7] Reenable extenstionDevelopmentPath flag --- src/browser.ts | 6 +++++- src/cli.ts | 3 ++- src/extester.ts | 4 ++-- src/util/codeUtil.ts | 7 ++++++- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/browser.ts b/src/browser.ts index 85e580d1e..ffc72e039 100644 --- a/src/browser.ts +++ b/src/browser.ts @@ -15,6 +15,7 @@ export class VSBrowser { static readonly browserName = 'vscode'; private storagePath: string; private extensionsFolder: string | undefined; + private extensionDevelopmentPath: string | undefined; private customSettings: Object; private _driver!: WebDriver; private codeVersion: string; @@ -25,6 +26,7 @@ export class 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.extensionDevelopmentPath = process.env.EXTENSION_DEV_PATH ? process.env.EXTENSION_DEV_PATH : undefined; this.customSettings = customSettings; this.codeVersion = codeVersion; this.releaseType = releaseType; @@ -76,6 +78,8 @@ export class VSBrowser { fs.copyFileSync(path.resolve(__dirname, '..', '..', 'resources', 'state.vscdb'), path.join(userSettings, 'globalStorage', 'state.vscdb')); } args.push(`--extensionDevelopmentPath=${process.cwd()}`); + } else if(this.extensionDevelopmentPath) { + args.push(`--extensionDevelopmentPath=${this.extensionDevelopmentPath}`); } let options = new Options().setChromeBinaryPath(codePath).addArguments(...args) as any; @@ -187,7 +191,7 @@ export class VSBrowser { return; } - const code = new CodeUtil(this.storagePath, this.releaseType, this.extensionsFolder); + const code = new CodeUtil(this.storagePath, this.releaseType, this.extensionsFolder, this.extensionDevelopmentPath); code.open(...paths); await new Promise(res => setTimeout(res, 3000)); await this.waitForWorkbench(); diff --git a/src/cli.ts b/src/cli.ts index 94cb58229..211b9c3eb 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -80,9 +80,10 @@ program.command('run-tests ') .option('-m, --mocha_config ', 'Path to Mocha configuration file') .option('-l, --log_level ', 'Log messages from webdriver with a given level', 'Info') .option('-f, --offline', 'Attempt to run without internet connection, make sure to have all requirements downloaded', false) + .option('-d, --extension_development_path ', 'VSCode will use the unpackaged extension source from this directory') .option('-r, --open_resource ', 'Open resources in VS Code. Multiple files and folders can be specified.') .action(withErrors(async (testFiles, cmd) => { - const extest = new ExTester(cmd.storage, codeStream(cmd.type), cmd.extensions_dir); + const extest = new ExTester(cmd.storage, codeStream(cmd.type), cmd.extensions_dir, cmd.extension_development_path); await extest.runTests(testFiles, {vscodeVersion: cmd.code_version, settings: cmd.code_settings, cleanup: cmd.uninstall_extension, config: cmd.mocha_config, logLevel: cmd.log_level, offline: cmd.offline, resources: cmd.open_resource ?? []}); })); diff --git a/src/extester.ts b/src/extester.ts index 20206d701..d8af5c8ab 100644 --- a/src/extester.ts +++ b/src/extester.ts @@ -44,8 +44,8 @@ export class ExTester { private code: CodeUtil; private chrome: DriverUtil; - constructor(storageFolder: string = DEFAULT_STORAGE_FOLDER, releaseType: ReleaseQuality = ReleaseQuality.Stable, extensionsDir?: string) { - this.code = new CodeUtil(storageFolder, releaseType, extensionsDir); + constructor(storageFolder: string = DEFAULT_STORAGE_FOLDER, releaseType: ReleaseQuality = ReleaseQuality.Stable, extensionsDir?: string, extensionDevPath?: string) { + this.code = new CodeUtil(storageFolder, releaseType, extensionsDir, extensionDevPath); this.chrome = new DriverUtil(storageFolder); if (process.versions.node.slice(0, 2) > NODEJS_VERSION_MAX) { diff --git a/src/util/codeUtil.ts b/src/util/codeUtil.ts index 2d8184766..7cd1aaa2a 100644 --- a/src/util/codeUtil.ts +++ b/src/util/codeUtil.ts @@ -28,6 +28,8 @@ export interface RunOptions { logLevel?: logging.Level; /** try to perform all setup without internet connection, needs all requirements pre-downloaded manually */ offline?: boolean; + /** path to unbundled extension sources */ + extensionDevelopmentPath?: string; /** list of resources to be opened by VS Code */ resources: string[]; } @@ -55,17 +57,19 @@ export class CodeUtil { private cliEnv!: string; private availableVersions: string[]; private extensionsFolder: string | undefined; + private extensionDevelopmentPath: string | undefined; /** * Create an instance of code handler * @param folder Path to folder where all the artifacts will be stored. * @param extensionsFolder Path to use as extensions directory by VS Code */ - constructor(folder: string = DEFAULT_STORAGE_FOLDER, type: ReleaseQuality = ReleaseQuality.Stable, extensionsFolder?: string) { + constructor(folder: string = DEFAULT_STORAGE_FOLDER, type: ReleaseQuality = ReleaseQuality.Stable, extensionsFolder?: string, extensionDevelopmentPath?: string) { this.availableVersions = []; this.downloadPlatform = this.getPlatform(); this.downloadFolder = path.resolve(folder); this.extensionsFolder = extensionsFolder ? path.resolve(extensionsFolder) : undefined; + this.extensionDevelopmentPath = extensionDevelopmentPath ? path.resolve(extensionDevelopmentPath) : undefined; this.releaseType = type; if (type === ReleaseQuality.Stable) { @@ -257,6 +261,7 @@ export class CodeUtil { process.env = finalEnv; process.env.TEST_RESOURCES = this.downloadFolder; process.env.EXTENSIONS_FOLDER = this.extensionsFolder; + process.env.EXTENSION_DEV_PATH = this.extensionDevelopmentPath; const runner = new VSRunner(this.executablePath, literalVersion, this.parseSettings(runOptions.settings ?? DEFAULT_RUN_OPTIONS.settings), runOptions.cleanup, this.releaseType, runOptions.config); return await runner.runTests(testFilesPattern, this, runOptions.logLevel, runOptions.resources); } From 815dfefa0beff71350d566e1f9e781bf135b618e Mon Sep 17 00:00:00 2001 From: Tami Takamiya Date: Sat, 10 Feb 2024 00:42:01 -0500 Subject: [PATCH 5/7] Generate code coverage report on test-project --- .gitignore | 1 + package.json | 3 ++- src/cli.ts | 6 ++++-- src/extester.ts | 6 +++++- src/util/codeUtil.ts | 7 +++++++ test/test-project/package.json | 4 +++- 6 files changed, 22 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 0bb05d1b8..2099076ac 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ resources/api-handler.vsix .npmrc *.tgz test/test-project/package-lock.json +test/test-project/coverage diff --git a/package.json b/package.json index 34c87fa17..c75e480f4 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,8 @@ "prebuild": "npm run build --workspaces", "build": "rimraf out/ && tsc && chmod a+x ./out/cli.js", "pretest": "npm run build && npm install --prefix test/test-project", - "test": "npm run ui-test --prefix test/test-project" + "test": "npm run ui-test --prefix test/test-project", + "coverage": "npm run build && npm run pretest && cd test/test-project && npm run ui-coverage" }, "repository": { "type": "git", diff --git a/src/cli.ts b/src/cli.ts index 211b9c3eb..30603165f 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -64,8 +64,9 @@ program.command('setup-tests') .option('-t, --type ', 'Type of VS Code release (stable/insider)') .option('-y, --yarn', 'Use yarn to build the extension via vsce instead of npm', false) .option('-i, --install_dependencies', 'Automatically install extensions your extension depends on', false) + .option('-d, --extension_development_path ', 'VSCode will use the unpackaged extension source from this directory') .action(withErrors(async (cmd) => { - const extest = new ExTester(cmd.storage, codeStream(cmd.type), cmd.extensions_dir); + const extest = new ExTester(cmd.storage, codeStream(cmd.type), cmd.extensions_dir, cmd.extension_development_path); await extest.setupRequirements({vscodeVersion: cmd.code_version, useYarn: cmd.yarn, installDependencies: cmd.install_dependencies}); })); @@ -100,9 +101,10 @@ program.command('setup-and-run ') .option('-i, --install_dependencies', 'Automatically install extensions your extension depends on', false) .option('-l, --log_level ', 'Log messages from webdriver with a given level', 'Info') .option('-f, --offline', 'Attempt to run without internet connection, make sure to have all requirements downloaded', false) + .option('-d, --extension_development_path ', 'VSCode will use the unpackaged extension source from this directory') .option('-r, --open_resource ', 'Open resources in VS Code. Multiple files and folders can be specified.') .action(withErrors(async (testFiles, cmd) => { - const extest = new ExTester(cmd.storage, codeStream(cmd.type), cmd.extensions_dir); + const extest = new ExTester(cmd.storage, codeStream(cmd.type), cmd.extensions_dir, cmd.extension_development_path); await extest.setupAndRunTests(testFiles, cmd.code_version, {useYarn: cmd.yarn, installDependencies: cmd.install_dependencies}, {settings: cmd.code_settings, cleanup: cmd.uninstall_extension, config: cmd.mocha_config, logLevel: cmd.log_level, resources: cmd.open_resource ?? []}); })); diff --git a/src/extester.ts b/src/extester.ts index d8af5c8ab..ddecc6400 100644 --- a/src/extester.ts +++ b/src/extester.ts @@ -133,7 +133,11 @@ export class ExTester { console.log(`Attempting with ChromeDriver ${actualChromeVersion} anyway. Tests may experience issues due to version mismatch.`); } } - await this.installVsix({useYarn}); + if (!this.code.extensionDevPath) { + await this.code.packageExtension(useYarn); + } else { + await this.installVsix({useYarn}); + } if (installDependencies && !offline) { this.code.installDependencies(); } diff --git a/src/util/codeUtil.ts b/src/util/codeUtil.ts index 7cd1aaa2a..b42902745 100644 --- a/src/util/codeUtil.ts +++ b/src/util/codeUtil.ts @@ -341,6 +341,13 @@ export class CodeUtil { return this.codeFolder; } + /** + * Getter for extension development path + */ + get extensionDevPath() { + return this.extensionDevelopmentPath; + } + /** * Check if given version is available in the given stream */ diff --git a/test/test-project/package.json b/test/test-project/package.json index 828d93794..d735456b7 100644 --- a/test/test-project/package.json +++ b/test/test-project/package.json @@ -170,7 +170,8 @@ "lint": "eslint src --ext .ts", "watch": "tsc -watch -p ./", "cb-init": "echo hello_ExTester | clipboard", - "ui-test": "npm run cb-init && extest setup-and-run './out/src/test/cli/order-3-test.js' './out/src/test/cli/order-2-test.js' './out/src/test/cli/order-1-test.js' './out/src/test/**/*-test.js' './out/src/test/system/clipboard.test.js' -u -i -r . -e ./test-extensions" + "ui-test": "npm run cb-init && extest setup-and-run './out/src/test/cli/order-3-test.js' './out/src/test/cli/order-2-test.js' './out/src/test/cli/order-1-test.js' './out/src/test/**/*-test.js' './out/src/test/system/clipboard.test.js' -u -i -r . -e ./test-extensions", + "ui-coverage": "npm run cb-init && npx c8 -r text -r html extest setup-and-run './out/src/test/cli/order-3-test.js' './out/src/test/cli/order-2-test.js' './out/src/test/cli/order-1-test.js' './out/src/test/**/*-test.js' './out/src/test/system/clipboard.test.js' -u -i -r . -e ./test-extensions -d ." }, "devDependencies": { "@types/chai": "^4.3.14", @@ -178,6 +179,7 @@ "@types/vscode": "^1.82.0", "@typescript-eslint/eslint-plugin": "^7.4.0", "@typescript-eslint/parser": "^7.4.0", + "c8": "^9.1.0", "chai": "^4.4.1", "clipboard-cli": "^4.0.0", "clipboardy": "^4.0.0", From f6cb2699318b3d6765fc7bcf6573eab4a16a701f Mon Sep 17 00:00:00 2001 From: Tami Takamiya Date: Mon, 25 Mar 2024 16:40:34 -0400 Subject: [PATCH 6/7] use npm --prefix flag --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c75e480f4..37b3cd5f4 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "build": "rimraf out/ && tsc && chmod a+x ./out/cli.js", "pretest": "npm run build && npm install --prefix test/test-project", "test": "npm run ui-test --prefix test/test-project", - "coverage": "npm run build && npm run pretest && cd test/test-project && npm run ui-coverage" + "coverage": "npm run build && npm run pretest && npm run ui-coverage --prefix test/test-project" }, "repository": { "type": "git", From f1ea0ff118b3daac13c9848f2ae1f195a0075c41 Mon Sep 17 00:00:00 2001 From: Tami Takamiya Date: Mon, 1 Apr 2024 11:02:44 -0400 Subject: [PATCH 7/7] coverage option support --- package-lock.json | 262 +++++++++++++++++++++++++++++++-- package.json | 1 + src/cli.ts | 7 +- src/extester.ts | 6 +- src/suite/runner.ts | 13 +- src/util/codeUtil.ts | 17 ++- src/util/coverage.ts | 84 +++++++++++ test/test-project/package.json | 3 +- 8 files changed, 372 insertions(+), 21 deletions(-) create mode 100644 src/util/coverage.ts diff --git a/package-lock.json b/package-lock.json index 47f2eb1ef..38e5eb01e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "dependencies": { "@types/selenium-webdriver": "^4.1.22", "@vscode/vsce": "^2.24.0", + "c8": "^9.1.0", "commander": "^12.0.0", "compare-versions": "^6.1.0", "fs-extra": "^11.2.0", @@ -61,6 +62,11 @@ "selenium-webdriver": ">=4.6.1" } }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==" + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "license": "ISC", @@ -143,6 +149,36 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "license": "MIT", @@ -189,6 +225,11 @@ "version": "4.0.4", "license": "MIT" }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==" + }, "node_modules/@types/js-yaml": { "version": "4.0.9", "dev": true, @@ -573,6 +614,68 @@ "version": "1.0.0", "license": "MIT" }, + "node_modules/c8": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/c8/-/c8-9.1.0.tgz", + "integrity": "sha512-mBWcT5iqNir1zIkzSPyI3NCR9EZCVI3WUD+AVO17MVWTSFNyUueXE82qTeampNtTr+ilN/5Ua3j24LgbCKjDVg==", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@istanbuljs/schema": "^0.1.3", + "find-up": "^5.0.0", + "foreground-child": "^3.1.1", + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.1.6", + "test-exclude": "^6.0.0", + "v8-to-istanbul": "^9.0.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1" + }, + "bin": { + "c8": "bin/c8.js" + }, + "engines": { + "node": ">=14.14.0" + } + }, + "node_modules/c8/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/c8/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/c8/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "engines": { + "node": ">=12" + } + }, "node_modules/cacheable-lookup": { "version": "7.0.0", "license": "MIT", @@ -789,6 +892,11 @@ "version": "0.0.1", "license": "MIT" }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + }, "node_modules/core-util-is": { "version": "1.0.3", "license": "MIT" @@ -995,7 +1103,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", - "peer": true, "engines": { "node": ">=6" } @@ -1064,7 +1171,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "peer": true, "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -1148,7 +1254,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "peer": true, "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -1253,7 +1358,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "peer": true, "engines": { "node": ">=8" } @@ -1294,6 +1398,11 @@ "node": ">=14" } }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==" + }, "node_modules/htmlparser2": { "version": "8.0.1", "funding": [ @@ -1533,6 +1642,50 @@ "node": ">=0.10.0" } }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jackspeak": { "version": "2.3.6", "license": "BlueOak-1.0.0", @@ -1636,7 +1789,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "peer": true, "dependencies": { "p-locate": "^5.0.0" }, @@ -1683,6 +1835,34 @@ "node": ">=10" } }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/markdown-it": { "version": "12.3.2", "license": "MIT", @@ -1989,7 +2169,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "peer": true, "dependencies": { "yocto-queue": "^0.1.0" }, @@ -2004,7 +2183,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "peer": true, "dependencies": { "p-limit": "^3.0.2" }, @@ -2051,7 +2229,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "peer": true, "engines": { "node": ">=8" } @@ -2287,7 +2464,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -2607,6 +2783,58 @@ "tar-fs": "^1.8.1" } }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/tmp": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", @@ -2718,6 +2946,19 @@ "version": "1.0.2", "license": "MIT" }, + "node_modules/v8-to-istanbul": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", + "integrity": "sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, "node_modules/vscode-extension-tester-locators": { "resolved": "locators", "link": true @@ -2745,7 +2986,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "peer": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -2827,7 +3067,6 @@ "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "peer": true, "engines": { "node": ">=10" } @@ -2897,7 +3136,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "peer": true, "engines": { "node": ">=10" }, diff --git a/package.json b/package.json index 37b3cd5f4..740e3c195 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,7 @@ "dependencies": { "@types/selenium-webdriver": "^4.1.22", "@vscode/vsce": "^2.24.0", + "c8": "^9.1.0", "commander": "^12.0.0", "compare-versions": "^6.1.0", "fs-extra": "^11.2.0", diff --git a/src/cli.ts b/src/cli.ts index 30603165f..1b44aa60a 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -65,6 +65,7 @@ program.command('setup-tests') .option('-y, --yarn', 'Use yarn to build the extension via vsce instead of npm', false) .option('-i, --install_dependencies', 'Automatically install extensions your extension depends on', false) .option('-d, --extension_development_path ', 'VSCode will use the unpackaged extension source from this directory') + .option('-C, --coverage', 'Enable code coverage using c8') .action(withErrors(async (cmd) => { const extest = new ExTester(cmd.storage, codeStream(cmd.type), cmd.extensions_dir, cmd.extension_development_path); await extest.setupRequirements({vscodeVersion: cmd.code_version, useYarn: cmd.yarn, installDependencies: cmd.install_dependencies}); @@ -82,9 +83,10 @@ program.command('run-tests ') .option('-l, --log_level ', 'Log messages from webdriver with a given level', 'Info') .option('-f, --offline', 'Attempt to run without internet connection, make sure to have all requirements downloaded', false) .option('-d, --extension_development_path ', 'VSCode will use the unpackaged extension source from this directory') + .option('-C, --coverage', 'Enable code coverage using c8') .option('-r, --open_resource ', 'Open resources in VS Code. Multiple files and folders can be specified.') .action(withErrors(async (testFiles, cmd) => { - const extest = new ExTester(cmd.storage, codeStream(cmd.type), cmd.extensions_dir, cmd.extension_development_path); + const extest = new ExTester(cmd.storage, codeStream(cmd.type), cmd.extensions_dir, cmd.extension_development_path, cmd.coverage); await extest.runTests(testFiles, {vscodeVersion: cmd.code_version, settings: cmd.code_settings, cleanup: cmd.uninstall_extension, config: cmd.mocha_config, logLevel: cmd.log_level, offline: cmd.offline, resources: cmd.open_resource ?? []}); })); @@ -102,9 +104,10 @@ program.command('setup-and-run ') .option('-l, --log_level ', 'Log messages from webdriver with a given level', 'Info') .option('-f, --offline', 'Attempt to run without internet connection, make sure to have all requirements downloaded', false) .option('-d, --extension_development_path ', 'VSCode will use the unpackaged extension source from this directory') + .option('-C, --coverage', 'Enable code coverage using c8') .option('-r, --open_resource ', 'Open resources in VS Code. Multiple files and folders can be specified.') .action(withErrors(async (testFiles, cmd) => { - const extest = new ExTester(cmd.storage, codeStream(cmd.type), cmd.extensions_dir, cmd.extension_development_path); + const extest = new ExTester(cmd.storage, codeStream(cmd.type), cmd.extensions_dir, cmd.extension_development_path, cmd.coverage); await extest.setupAndRunTests(testFiles, cmd.code_version, {useYarn: cmd.yarn, installDependencies: cmd.install_dependencies}, {settings: cmd.code_settings, cleanup: cmd.uninstall_extension, config: cmd.mocha_config, logLevel: cmd.log_level, resources: cmd.open_resource ?? []}); })); diff --git a/src/extester.ts b/src/extester.ts index ddecc6400..e16f4d2a7 100644 --- a/src/extester.ts +++ b/src/extester.ts @@ -44,8 +44,8 @@ export class ExTester { private code: CodeUtil; private chrome: DriverUtil; - constructor(storageFolder: string = DEFAULT_STORAGE_FOLDER, releaseType: ReleaseQuality = ReleaseQuality.Stable, extensionsDir?: string, extensionDevPath?: string) { - this.code = new CodeUtil(storageFolder, releaseType, extensionsDir, extensionDevPath); + constructor(storageFolder: string = DEFAULT_STORAGE_FOLDER, releaseType: ReleaseQuality = ReleaseQuality.Stable, extensionsDir?: string, extensionDevPath?: string, coverage?: boolean) { + this.code = new CodeUtil(storageFolder, releaseType, extensionsDir, extensionDevPath, coverage); this.chrome = new DriverUtil(storageFolder); if (process.versions.node.slice(0, 2) > NODEJS_VERSION_MAX) { @@ -133,7 +133,7 @@ export class ExTester { console.log(`Attempting with ChromeDriver ${actualChromeVersion} anyway. Tests may experience issues due to version mismatch.`); } } - if (!this.code.extensionDevPath) { + if (this.code.extensionDevPath) { await this.code.packageExtension(useYarn); } else { await this.installVsix({useYarn}); diff --git a/src/suite/runner.ts b/src/suite/runner.ts index f39ff1300..7f908aef7 100644 --- a/src/suite/runner.ts +++ b/src/suite/runner.ts @@ -10,6 +10,7 @@ import * as yaml from 'js-yaml'; import sanitize from 'sanitize-filename'; import { logging } from 'selenium-webdriver'; import * as os from 'os'; +import { Coverage } from '../util/coverage'; /** * Mocha runner wrapper @@ -43,6 +44,7 @@ export class VSRunner { return new Promise(resolve => { let self = this; let browser: VSBrowser = new VSBrowser(this.codeVersion, this.releaseType, this.customSettings, logLevel); + let coverage: Coverage | undefined; const testFiles = new Set(); for (const pattern of testFilesPattern) { @@ -65,6 +67,12 @@ export class VSRunner { this.mocha.suite.beforeAll(async function () { this.timeout(180000); + + if (code.coverageEnabled) { + coverage = new Coverage(); + process.env.NODE_V8_COVERAGE = coverage?.targetDir; + } + const start = Date.now(); const binPath = process.platform === 'darwin' ? await self.createShortcut(code.getCodeFolder(), self.tmpLink) : self.chromeBin; await browser.start(binPath); @@ -88,7 +96,10 @@ export class VSRunner { } } - code.uninstallExtension(self.cleanup); + if (!code.extensionDevPath) { + code.uninstallExtension(self.cleanup); + } + await coverage?.write(); }); this.mocha.run((failures) => { diff --git a/src/util/codeUtil.ts b/src/util/codeUtil.ts index b42902745..1be06823b 100644 --- a/src/util/codeUtil.ts +++ b/src/util/codeUtil.ts @@ -58,20 +58,27 @@ export class CodeUtil { private availableVersions: string[]; private extensionsFolder: string | undefined; private extensionDevelopmentPath: string | undefined; + private coverage: boolean | undefined; /** * Create an instance of code handler * @param folder Path to folder where all the artifacts will be stored. * @param extensionsFolder Path to use as extensions directory by VS Code */ - constructor(folder: string = DEFAULT_STORAGE_FOLDER, type: ReleaseQuality = ReleaseQuality.Stable, extensionsFolder?: string, extensionDevelopmentPath?: string) { + constructor(folder: string = DEFAULT_STORAGE_FOLDER, type: ReleaseQuality = ReleaseQuality.Stable, extensionsFolder?: string, extensionDevelopmentPath?: string, coverage?: boolean) { this.availableVersions = []; this.downloadPlatform = this.getPlatform(); this.downloadFolder = path.resolve(folder); this.extensionsFolder = extensionsFolder ? path.resolve(extensionsFolder) : undefined; this.extensionDevelopmentPath = extensionDevelopmentPath ? path.resolve(extensionDevelopmentPath) : undefined; + this.coverage = coverage; this.releaseType = type; + // If code coverage is enabled, but extensionDevelopmentPath is not, assume that extensionDevelopmentPath is the current directory. + if (this.coverage && !this.extensionDevelopmentPath) { + this.extensionDevelopmentPath = path.resolve("."); + } + if (type === ReleaseQuality.Stable) { this.codeFolder = path.join(this.downloadFolder, (process.platform === 'darwin') ? 'Visual Studio Code.app' : `VSCode-${this.downloadPlatform}`); @@ -232,6 +239,7 @@ export class CodeUtil { if (this.extensionsFolder) { command += ` --extensions-dir=${this.extensionsFolder}`; } + console.log(`command:${command}`); child_process.execSync(command, { stdio: 'inherit' }); } } @@ -348,6 +356,13 @@ export class CodeUtil { return this.extensionDevelopmentPath; } + /** + * Getter for coverage enablement option + */ + get coverageEnabled() { + return this.coverage; + } + /** * Check if given version is available in the given stream */ diff --git a/src/util/coverage.ts b/src/util/coverage.ts new file mode 100644 index 000000000..565dfae95 --- /dev/null +++ b/src/util/coverage.ts @@ -0,0 +1,84 @@ +/*--------------------------------------------------------- + * Copyright (C) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------*/ + +/*--------------------------------------------------------- + * Modified for vscode-extension-tester + *--------------------------------------------------------*/ + +import { Report } from 'c8'; +import { randomUUID } from 'crypto'; +import { promises as fs, mkdirSync } from 'fs'; +import { tmpdir } from 'os'; +import { join } from 'path'; + +/** + * Manages collecting coverage data from test runs. All runs, regardless of + * platform, expect coverage data given in the V8 coverage format. We then + * use c8 to convert it to the common Istanbul format and represent it with + * a variety of reporters. + */ +export class Coverage { + public readonly targetDir = join(tmpdir(), `vsc-coverage-${randomUUID()}`); + + constructor() { + mkdirSync(this.targetDir, { recursive: true }); + } + + public async write() { + try { + const report = new Report({ + "reporter": ["text", "html"], + "all": false, + "excludeNodeModules": true, + "include": [], + "exclude": [ + "coverage/**", + "packages/*/test{,s}/**", + "**/*.d.ts", + "test{,s}/**", + "test{,-*}.{js,cjs,mjs,ts,tsx,jsx}", + "**/*{.,-}test.{js,cjs,mjs,ts,tsx,jsx}", + "**/__tests__/**", + "**/{ava,babel,nyc}.config.{js,cjs,mjs}", + "**/jest.config.{js,cjs,mjs,ts}", + "**/{karma,rollup,webpack}.config.js", + "**/.{eslint,mocha}rc.{js,cjs}" + ], + "extension": [ + ".js", + ".cjs", + ".mjs", + ".ts", + ".tsx", + ".jsx" + ], + "excludeAfterRemap": false, + "skipFull": false, + "tempDirectory": this.targetDir, + "resolve": "", + "omitRelative": true, + "allowExternal": false, + }); + + // A hacky fix due to an outstanding bug in Istanbul's exclusion testing + // code: its subdirectory checks are case-sensitive on Windows, but file + // URIs might have mixed casing. + // + // Setting `relativePath: false` on the exclude bypasses this code path. + // + // https://github.com/istanbuljs/test-exclude/issues/43 + // https://github.com/istanbuljs/test-exclude/blob/a5b1d07584109f5f553ccef97de64c6cbfca4764/index.js#L91 + (report as any).exclude.relativePath = false; + + await report.run(); + } catch (e) { + // throw new CliExpectedError( + throw new Error( + `Coverage report generated failed, please file an issue with original reports located in ${this.targetDir}:\n\n${e}`, + ); + } + + await fs.rm(this.targetDir, { recursive: true, force: true }); + } +} diff --git a/test/test-project/package.json b/test/test-project/package.json index d735456b7..fb979aa49 100644 --- a/test/test-project/package.json +++ b/test/test-project/package.json @@ -171,7 +171,7 @@ "watch": "tsc -watch -p ./", "cb-init": "echo hello_ExTester | clipboard", "ui-test": "npm run cb-init && extest setup-and-run './out/src/test/cli/order-3-test.js' './out/src/test/cli/order-2-test.js' './out/src/test/cli/order-1-test.js' './out/src/test/**/*-test.js' './out/src/test/system/clipboard.test.js' -u -i -r . -e ./test-extensions", - "ui-coverage": "npm run cb-init && npx c8 -r text -r html extest setup-and-run './out/src/test/cli/order-3-test.js' './out/src/test/cli/order-2-test.js' './out/src/test/cli/order-1-test.js' './out/src/test/**/*-test.js' './out/src/test/system/clipboard.test.js' -u -i -r . -e ./test-extensions -d ." + "ui-coverage": "npm run cb-init && extest setup-and-run './out/src/test/cli/order-3-test.js' './out/src/test/cli/order-2-test.js' './out/src/test/cli/order-1-test.js' './out/src/test/**/*-test.js' './out/src/test/system/clipboard.test.js' -u -i -r . -e ./test-extensions --coverage" }, "devDependencies": { "@types/chai": "^4.3.14", @@ -179,7 +179,6 @@ "@types/vscode": "^1.82.0", "@typescript-eslint/eslint-plugin": "^7.4.0", "@typescript-eslint/parser": "^7.4.0", - "c8": "^9.1.0", "chai": "^4.4.1", "clipboard-cli": "^4.0.0", "clipboardy": "^4.0.0",