@vscode/test-web
Advanced tools
Comparing version 0.0.13 to 0.0.14
# Changelog | ||
## 0.0.14 | ||
* new option `--extensionPath` : A path pointing to a folder containing additional extensions to include. Argument can be provided multiple times. | ||
* new option `--permission`: Permission granted to the opened browser: e.g. clipboard-read, clipboard-write. See full list of options [here](https://playwright.dev/docs/1.14/emulation#permissions). Argument can be provided multiple times. | ||
* new option `--hideServerLog`: If set, hides the server log. Defaults to true when an extensionTestsPath is provided, otherwise false. | ||
* close server when browser is closed | ||
## 0.0.9 | ||
* new option `folderPath`: A local folder to open VS Code on. The folder content will be available as a virtual file system and opened as workspace. | ||
### 0.0.1 | | ||
@@ -4,0 +15,0 @@ |
@@ -28,7 +28,7 @@ /******/ (() => { // webpackBootstrap | ||
function isEntry(e) { | ||
return e && (e.type == vscode_1.FileType.Directory || e.type == vscode_1.FileType.File) && typeof e.name === 'string' && e.name.length > 0; | ||
return e && (e.type === vscode_1.FileType.Directory || e.type === vscode_1.FileType.File) && typeof e.name === 'string' && e.name.length > 0; | ||
} | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
function isStat(e) { | ||
return e && (e.type == vscode_1.FileType.Directory || e.type == vscode_1.FileType.File) && typeof e.ctime === 'number' && typeof e.mtime === 'number' && typeof e.size === 'number'; | ||
return e && (e.type === vscode_1.FileType.Directory || e.type === vscode_1.FileType.File) && typeof e.ctime === 'number' && typeof e.mtime === 'number' && typeof e.size === 'number'; | ||
} | ||
@@ -559,3 +559,3 @@ function newFileStat(type, size) { | ||
context.subscriptions.push(disposable); | ||
console.log(`vscode-test-web-support fs provider registeres for ${fsProvider_1.SCHEME}, mount ${serverUri.toString()}`); | ||
console.log(`vscode-test-web-support fs provider registers for ${fsProvider_1.SCHEME}, initial content from ${serverUri.toString()}`); | ||
} | ||
@@ -562,0 +562,0 @@ exports.activate = activate; |
@@ -45,2 +45,6 @@ #!/usr/bin/env node | ||
/** | ||
* Do not show the server log. Defaults to `true` if a extensionTestsPath is provided, `false` otherwise. | ||
*/ | ||
hideServerLog?: boolean; | ||
/** | ||
* Expose browser debugging on this port number, and wait for the debugger to attach before running tests. | ||
@@ -60,3 +64,16 @@ */ | ||
folderUri?: string; | ||
/** | ||
* Permissions granted to the opened browser. An list of permissions can be found at | ||
* https://playwright.dev/docs/api/class-browsercontext#browser-context-grant-permissions | ||
* Example: [ 'clipboard-read', 'clipboard-write' ] | ||
*/ | ||
permissions?: string[]; | ||
/** | ||
* Absolute paths pointing to built-in extensions to include. | ||
*/ | ||
extensionPaths?: string[]; | ||
} | ||
export interface Disposable { | ||
dispose(): void; | ||
} | ||
/** | ||
@@ -70,2 +87,2 @@ * Runs the tests in a browser. | ||
}): Promise<void>; | ||
export declare function open(options: Options): Promise<void>; | ||
export declare function open(options: Options): Promise<Disposable>; |
216
out/index.js
@@ -21,3 +21,2 @@ #!/usr/bin/env node | ||
async function runTests(options) { | ||
var _a; | ||
const config = { | ||
@@ -28,19 +27,32 @@ extensionDevelopmentPath: options.extensionDevelopmentPath, | ||
folderUri: options.folderUri, | ||
folderMountPath: options.folderPath | ||
folderMountPath: options.folderPath, | ||
hideServerLog: true, | ||
extensionPaths: options.extensionPaths | ||
}; | ||
const port = 3000; | ||
const server = await (0, main_1.runServer)(port, config); | ||
const endpoint = `http://localhost:${port}`; | ||
const result = await openInBrowser({ | ||
browserType: options.browserType, | ||
endpoint, | ||
headless: (_a = options.headless) !== null && _a !== void 0 ? _a : true, | ||
devTools: options.devTools, | ||
waitForDebugger: options.waitForDebugger, | ||
return new Promise(async (s, e) => { | ||
const endpoint = `http://localhost:${port}`; | ||
const context = await openBrowser(endpoint, options); | ||
context.once('close', () => server.close()); | ||
await context.exposeFunction('codeAutomationLog', (type, args) => { | ||
console[type](...args); | ||
}); | ||
await context.exposeFunction('codeAutomationExit', async (code) => { | ||
var _a; | ||
try { | ||
await ((_a = context.browser()) === null || _a === void 0 ? void 0 : _a.close()); | ||
} | ||
catch (error) { | ||
console.error(`Error when closing browser: ${error}`); | ||
} | ||
server.close(); | ||
if (code === 0) { | ||
s(); | ||
} | ||
else { | ||
e(new Error('Test failed')); | ||
} | ||
}); | ||
}); | ||
server.close(); | ||
if (result) { | ||
return; | ||
} | ||
throw new Error('Test failed'); | ||
} | ||
@@ -55,19 +67,22 @@ exports.runTests = runTests; | ||
async function open(options) { | ||
var _a; | ||
const config = { | ||
extensionDevelopmentPath: options.extensionDevelopmentPath, | ||
extensionTestsPath: options.extensionTestsPath, | ||
build: await getBuild(options.version), | ||
folderUri: options.folderUri, | ||
folderMountPath: options.folderPath | ||
folderMountPath: options.folderPath, | ||
extensionPaths: options.extensionPaths | ||
}; | ||
const port = 3000; | ||
await (0, main_1.runServer)(port, config); | ||
const server = await (0, main_1.runServer)(port, config); | ||
const endpoint = `http://localhost:${port}`; | ||
await openInBrowser({ | ||
browserType: options.browserType, | ||
endpoint, | ||
headless: (_a = options.headless) !== null && _a !== void 0 ? _a : false, | ||
devTools: options.devTools, | ||
waitForDebugger: options.waitForDebugger | ||
}); | ||
const context = await openBrowser(endpoint, options); | ||
context.once('close', () => server.close()); | ||
return { | ||
dispose: () => { | ||
var _a; | ||
server.close(); | ||
(_a = context.browser()) === null || _a === void 0 ? void 0 : _a.close(); | ||
} | ||
}; | ||
} | ||
@@ -77,33 +92,35 @@ exports.open = open; | ||
const height = 800; | ||
function openInBrowser(options) { | ||
return new Promise(async (s) => { | ||
var _a; | ||
const args = []; | ||
if (process.platform === 'linux' && options.browserType === 'chromium') { | ||
args.push('--no-sandbox'); | ||
} | ||
if (options.waitForDebugger) { | ||
args.push(`--remote-debugging-port=${options.waitForDebugger}`); | ||
} | ||
const browser = await playwright[options.browserType].launch({ headless: options.headless, args, devtools: options.devTools }); | ||
const context = await browser.newContext(); | ||
const page = (_a = context.pages()[0]) !== null && _a !== void 0 ? _a : await context.newPage(); | ||
if (options.waitForDebugger) { | ||
await page.waitForFunction(() => '__jsDebugIsReady' in globalThis); | ||
} | ||
await page.setViewportSize({ width, height }); | ||
await page.goto(options.endpoint); | ||
await page.exposeFunction('codeAutomationLog', (type, args) => { | ||
console[type](...args); | ||
}); | ||
await page.exposeFunction('codeAutomationExit', async (code) => { | ||
try { | ||
await browser.close(); | ||
async function openBrowser(endpoint, options) { | ||
var _a, _b; | ||
const args = []; | ||
if (process.platform === 'linux' && options.browserType === 'chromium') { | ||
args.push('--no-sandbox'); | ||
} | ||
if (options.waitForDebugger) { | ||
args.push(`--remote-debugging-port=${options.waitForDebugger}`); | ||
} | ||
const headless = (_a = options.headless) !== null && _a !== void 0 ? _a : options.extensionDevelopmentPath !== undefined; | ||
const browser = await playwright[options.browserType].launch({ headless, args, devtools: options.devTools }); | ||
const context = await browser.newContext(); | ||
if (options.permissions) { | ||
context.grantPermissions(options.permissions); | ||
} | ||
// forcefully close browser if last page is closed. workaround for https://github.com/microsoft/playwright/issues/2946 | ||
let openPages = 0; | ||
context.on('page', page => { | ||
openPages++; | ||
page.once('close', () => { | ||
openPages--; | ||
if (openPages === 0) { | ||
browser.close(); | ||
} | ||
catch (error) { | ||
console.error(`Error when closing browser: ${error}`); | ||
} | ||
s(code === 0); | ||
}); | ||
}); | ||
const page = (_b = context.pages()[0]) !== null && _b !== void 0 ? _b : await context.newPage(); | ||
if (options.waitForDebugger) { | ||
await page.waitForFunction(() => '__jsDebugIsReady' in globalThis); | ||
} | ||
await page.setViewportSize({ width, height }); | ||
await page.goto(endpoint); | ||
return context; | ||
} | ||
@@ -133,3 +150,3 @@ function validateStringOrUndefined(options, name) { | ||
function valdiateBrowserType(browserType) { | ||
if (browserType === 'undefined') { | ||
if (browserType === undefined) { | ||
return 'chromium'; | ||
@@ -144,2 +161,42 @@ } | ||
} | ||
function valdiatePermissions(permissions) { | ||
if (permissions === undefined) { | ||
return undefined; | ||
} | ||
function isValidPermission(p) { | ||
return typeof p === 'string'; | ||
} | ||
if (isValidPermission(permissions)) { | ||
return [permissions]; | ||
} | ||
if (Array.isArray(permissions) && permissions.every(isValidPermission)) { | ||
return permissions; | ||
} | ||
console.log(`Invalid permission`); | ||
showHelp(); | ||
process.exit(-1); | ||
} | ||
async function valdiateExtensionPaths(extensionPaths) { | ||
if (extensionPaths === undefined) { | ||
return undefined; | ||
} | ||
if (!Array.isArray(extensionPaths)) { | ||
extensionPaths = [extensionPaths]; | ||
} | ||
if (Array.isArray(extensionPaths)) { | ||
const res = []; | ||
for (const extensionPath of extensionPaths) { | ||
if (typeof extensionPath === 'string') { | ||
res.push(await validatePath(extensionPath)); | ||
} | ||
else { | ||
break; | ||
} | ||
} | ||
return res; | ||
} | ||
console.log(`Invalid extensionPath`); | ||
showHelp(); | ||
process.exit(-1); | ||
} | ||
async function validatePath(loc, isFile) { | ||
@@ -180,20 +237,37 @@ loc = path.resolve(loc); | ||
console.log('Usage:'); | ||
console.log(` --browserType 'chromium' | 'firefox' | 'webkit': The browser to launch`); | ||
console.log(` --extensionDevelopmentPath path. [Optional]: A path pointing to a extension to include.`); | ||
console.log(` --extensionTestsPath path. [Optional]: A path to a test module to run`); | ||
console.log(` --version. 'insiders' (Default) | 'stable' | 'sources' [Optional]`); | ||
console.log(` --open-devtools. Opens the dev tools [Optional]`); | ||
console.log(` --headless. Whether to show the browser. Defaults to true when an extensionTestsPath is provided, otherwise false. [Optional]`); | ||
console.log(` folderPath. A local folder to open VS Code on. The folder content will be available as a virtual file system`); | ||
console.log(` --browserType 'chromium' | 'firefox' | 'webkit': The browser to launch. [Optional, default 'chromium']`); | ||
console.log(` --extensionDevelopmentPath path: A path pointing to an extension under development to include. [Optional]`); | ||
console.log(` --extensionTestsPath path: A path to a test module to run. [Optional]`); | ||
console.log(` --version 'insiders' | 'stable' | 'sources' [Optional, default 'insiders']`); | ||
console.log(` --open-devtools: If set, opens the dev tools [Optional]`); | ||
console.log(` --headless: Whether to hide the browser. Defaults to true when an extensionTestsPath is provided, otherwise false. [Optional]`); | ||
console.log(` --hideServerLog: Whether to hide the server log. Defaults to true when an extensionTestsPath is provided, otherwise false. [Optional]`); | ||
console.log(` --permission: Permission granted in the opened browser: e.g. 'clipboard-read', 'clipboard-write': [Optional, Multiple]`); | ||
console.log(` --folder-uri: workspace to open VS Code on. Ignored when folderPath is provided [Optional]`); | ||
console.log(` --extensionPath: A path pointing to a folder containing additional extensions to include [Optional, Multiple]`); | ||
console.log(` folderPath. A local folder to open VS Code on. The folder content will be available as a virtual file system. [Optional]`); | ||
} | ||
async function cliMain() { | ||
const options = { string: ['extensionDevelopmentPath', 'extensionTestsPath', 'browserType', 'version', 'waitForDebugger', 'folder-uri', 'mount'], boolean: ['open-devtools', 'headless'] }; | ||
const options = { | ||
string: ['extensionDevelopmentPath', 'extensionTestsPath', 'browserType', 'version', 'waitForDebugger', 'folder-uri', 'permission', 'extensionPath'], | ||
boolean: ['open-devtools', 'headless', 'hideServerLog'], | ||
unknown: arg => { | ||
if (arg.startsWith('-')) { | ||
console.log(`Unknown argument ${arg}`); | ||
return false; | ||
} | ||
return true; | ||
} | ||
}; | ||
const args = minimist(process.argv.slice(2), options); | ||
const browserType = valdiateBrowserType(args.browserType); | ||
const version = validateVersion(args.version); | ||
const extensionTestsPath = await validatePathOrUndefined(args, 'extensionTestsPath', true); | ||
const extensionDevelopmentPath = await validatePathOrUndefined(args, 'extensionDevelopmentPath'); | ||
const extensionPaths = await valdiateExtensionPaths(args.extensionPath); | ||
const version = validateVersion(args.version); | ||
const devTools = validateBooleanOrUndefined(args, 'open-devtools'); | ||
const headless = validateBooleanOrUndefined(args, 'headless'); | ||
const devTools = validateBooleanOrUndefined(args, 'open-devtools'); | ||
const port = validatePortNumber(args.waitForDebugger); | ||
const permissions = valdiatePermissions(args.permission); | ||
const hideServerLog = validateBooleanOrUndefined(args, 'hideServerLog'); | ||
const waitForDebugger = validatePortNumber(args.waitForDebugger); | ||
let folderUri = validateStringOrUndefined(args, 'folder-uri'); | ||
@@ -219,6 +293,9 @@ let folderPath; | ||
devTools, | ||
waitForDebugger: port, | ||
waitForDebugger, | ||
folderUri, | ||
folderPath, | ||
headless | ||
headless, | ||
hideServerLog, | ||
permissions, | ||
extensionPaths | ||
}); | ||
@@ -232,6 +309,9 @@ } | ||
devTools, | ||
waitForDebugger: port, | ||
waitForDebugger, | ||
folderUri, | ||
folderPath, | ||
headless | ||
headless, | ||
hideServerLog, | ||
permissions, | ||
extensionPaths | ||
}); | ||
@@ -238,0 +318,0 @@ } |
@@ -16,3 +16,5 @@ "use strict"; | ||
const app = new Koa(); | ||
app.use(morgan('dev')); | ||
if (!config.hideServerLog) { | ||
app.use(morgan('dev')); | ||
} | ||
// this is here such that the iframe worker can fetch the extension files | ||
@@ -24,6 +26,2 @@ app.use((ctx, next) => { | ||
app.use(kmount('/static', kstatic(path.join(__dirname, '../static')))); | ||
if (config.extensionPath) { | ||
console.log('Serving extensions from ' + config.extensionPath); | ||
app.use(kmount('/static/extensions', kstatic(config.extensionPath, { hidden: true }))); | ||
} | ||
if (config.extensionDevelopmentPath) { | ||
@@ -37,2 +35,8 @@ console.log('Serving dev extensions from ' + config.extensionDevelopmentPath); | ||
(0, mounts_1.configureMounts)(config, app); | ||
if (config.extensionPaths) { | ||
config.extensionPaths.forEach((extensionPath, index) => { | ||
console.log('Serving additional built-in extensions from ' + extensionPath); | ||
app.use(kmount(`/static/extensions/${index}`, kstatic(extensionPath, { hidden: true }))); | ||
}); | ||
} | ||
app.use((0, workbench_1.default)(config)); | ||
@@ -39,0 +43,0 @@ return app; |
@@ -14,3 +14,3 @@ "use strict"; | ||
const mountPrefix = '/static/mount'; | ||
exports.fsProviderExtensionPrefix = '/static/fsproviderextension'; | ||
exports.fsProviderExtensionPrefix = '/static/extensions/fs'; | ||
exports.fsProviderFolderUri = 'vscode-test-web://mount/'; | ||
@@ -17,0 +17,0 @@ function configureMounts(config, app) { |
@@ -55,8 +55,10 @@ "use strict"; | ||
const options = {}; | ||
if (config.extensionPath) { | ||
options.additionalBuiltinExtensions = await (0, extensions_1.scanForExtensions)(config.extensionPath, { | ||
scheme: ctx.protocol, | ||
authority: ctx.host, | ||
path: '/static/extensions', | ||
}); | ||
if (config.extensionPaths) { | ||
await Promise.all(config.extensionPaths.map(async (extensionPath, index) => { | ||
options.additionalBuiltinExtensions = await (0, extensions_1.scanForExtensions)(extensionPath, { | ||
scheme: ctx.protocol, | ||
authority: ctx.host, | ||
path: `/static/extensions/${index}`, | ||
}); | ||
})); | ||
} | ||
@@ -63,0 +65,0 @@ if (config.extensionDevelopmentPath) { |
{ | ||
"name": "@vscode/test-web", | ||
"version": "0.0.13", | ||
"version": "0.0.14", | ||
"scripts": { | ||
"init": "yarn --cwd=fs-provider && yarn --cwd=sample", | ||
"install-extensions": "yarn --cwd=fs-provider && yarn --cwd=sample", | ||
"compile": "tsc -p ./ && yarn compile-fs-provider", | ||
@@ -7,0 +7,0 @@ "watch": "tsc -w -p ./", |
# @vscode/test-web | ||
![Test Status Badge](https://github.com/microsoft/vscode-test-web/workflows/Tests/badge.svg) | ||
This module helps testing [VS Code web extensions](https://code.visualstudio.com/api/extension-guides/web-extensions) locally. | ||
[![Test Status Badge](https://github.com/microsoft/vscode-test-web/workflows/Tests/badge.svg)](https://github.com/microsoft/vscode-test-web/actions/workflows/tests.yml) | ||
[![npm Package](https://img.shields.io/npm/v/@vscode/test-web.svg?style=flat-square)](https://www.npmjs.org/package/@vscode/test-web) | ||
[![NPM Downloads](https://img.shields.io/npm/dm/@vscode/test-web.svg)](https://npmjs.org/package/@vscode/test-web) | ||
The node module runs a local web server that serves VS Code for the browser including the extensions located at the given local path. Additionally the extension tests are automatically run. | ||
@@ -33,3 +36,3 @@ | ||
VS Code Browser will open on a virtual workspace (scheme `vscode-test-web`), backed by a file system provider that gets the file/folder data from the local disk. Changes to the file system are kept in memory and are not written back to disk. | ||
VS Code for the Web will open on a virtual workspace (scheme `vscode-test-web`), backed by a file system provider that gets the file/folder data from the local disk. Changes to the file system are kept in memory and are not written back to disk. | ||
@@ -59,12 +62,16 @@ Via API: | ||
CLI options: | ||
``` | ||
--browserType 'chromium' | 'firefox' | 'webkit': The browser to launch | ||
--extensionDevelopmentPath path. [Optional]: A path pointing to a extension to include. | ||
--extensionTestsPath path. [Optional]: A path to a test module to run | ||
--version. 'insiders' (Default) | 'stable' | 'sources' [Optional] | ||
--open-devtools. Opens the dev tools [Optional] | ||
--headless. Whether to show the browser. Defaults to true when an extensionTestsPath is provided, otherwise false. [Optional] | ||
folderPath. A local folder to open VS Code on. The folder content will be available as a virtual file system` | ||
``` | ||
|Option|Argument Description|| | ||
|-----|-----|----| | ||
| --browserType | The browser to launch: `chromium` (default), `firefox` or `webkit` | | ||
| --extensionDevelopmentPath | A path pointing to an extension under development to include. | | ||
| --extensionTestsPath | A path to a test module to run. | | ||
| --version | `insiders` (default), `stable` or `sources`.<br>For sources, also run `yarn web` in a vscode repo | | ||
| --open-devtools| If set, opens the dev tools | | ||
| --headless| If set, hides the browser. Defaults to true when an extensionTestsPath is provided, otherwise false. | | ||
| --hideServerLog| If set, hides the server log. Defaults to true when an extensionTestsPath is provided, otherwise false. | | ||
| --permission| Permission granted to the opened browser: e.g. `clipboard-read`, `clipboard-write`. See [full list of options](https://playwright.dev/docs/api/class-browsercontext#browser-context-grant-permissions). Argument can be provided multiple times. | | ||
| --folder-uri | URI of the workspace to open VS Code on. Ignored when `folderPath` is provided | | ||
| --extensionPath | A path pointing to a folder containing additional extensions to include. Argument can be provided multiple times. | | ||
| folderPath | A local folder to open VS Code on. The folder content will be available as a virtual file system and opened as workspace. | | ||
@@ -75,3 +82,3 @@ Corresponding options are available in the API. | ||
- `yarn install` | ||
- `yarn && yarn install-extensions` | ||
- Make necessary changes in [`src`](./src) | ||
@@ -78,0 +85,0 @@ - `yarn compile` (or `yarn watch`) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
113672
17
2060
106