diff --git a/package.json b/package.json index d3d2a900..bbe88c8c 100644 --- a/package.json +++ b/package.json @@ -207,8 +207,23 @@ "markdownDescription": "The arguments to pass to the shell executable. This is applied only when `vitest.shellType` is `terminal`.", "type": "array", "scope": "resource" + }, + "vitest.previewBrowser": { + "markdownDescription": "Open the visible browser when running tests in the Browser Mode.", + "type": "boolean", + "default": false, + "scope": "resource" } } + }, + "views": { + "test": [ + { + "type": "webview", + "id": "vitest.webviewSettings", + "name": "Vitest" + } + ] } }, "scripts": { diff --git a/src/config.ts b/src/config.ts index a35dbf72..a974c55a 100644 --- a/src/config.ts +++ b/src/config.ts @@ -59,10 +59,13 @@ export function getConfig(workspaceFolder?: WorkspaceFolder) { const shellType = get<'child_process' | 'terminal'>('shellType', 'child_process') const nodeExecArgs = get('nodeExecArgs') + const previewBrowser = get('previewBrowser', false) + return { env: get>('nodeEnv', null), debugExclude: get('debugExclude', []), filesWatcherInclude, + previewBrowser, terminalShellArgs, terminalShellPath, shellType, diff --git a/src/extension.ts b/src/extension.ts index 30215cb0..bbaa05fc 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -16,9 +16,10 @@ import { TagsManager } from './tagsManager' import { coverageContext } from './coverage' import { debugTests } from './debug/api' import { VitestTerminalProcess } from './api/terminal' +import { SettingsWebview } from './settingsWebview' export async function activate(context: vscode.ExtensionContext) { - const extension = new VitestExtension() + const extension = new VitestExtension(context) context.subscriptions.push(extension) await extension.activate() } @@ -39,7 +40,7 @@ class VitestExtension { private disposables: vscode.Disposable[] = [] - constructor() { + constructor(private context: vscode.ExtensionContext) { log.info(`[v${version}] Vitest extension is activated because Vitest is installed or there is a Vite/Vitest config file in the workspace.`) this.testController = vscode.tests.createTestController(testControllerId, 'Vitest') @@ -284,6 +285,7 @@ class VitestExtension { 'vitest.terminalShellPath', ] + const settingsWebview = new SettingsWebview(this.context.extensionUri) this.disposables = [ vscode.workspace.onDidChangeConfiguration((event) => { if (reloadConfigNames.some(x => event.affectsConfiguration(x))) @@ -335,6 +337,7 @@ class VitestExtension { const tokenSource = new vscode.CancellationTokenSource() await profile.runHandler(request, tokenSource.token) }), + settingsWebview, ] // if the config changes, re-define all test profiles diff --git a/src/settingsWebview.ts b/src/settingsWebview.ts new file mode 100644 index 00000000..718a643c --- /dev/null +++ b/src/settingsWebview.ts @@ -0,0 +1,117 @@ +import * as vscode from 'vscode' +import { getConfig } from './config' +import { nanoid } from './utils' + +export class SettingsWebview implements vscode.WebviewViewProvider, vscode.Disposable { + private disposables: vscode.Disposable[] + private view: vscode.WebviewView | undefined + + constructor( + private extensionUri: vscode.Uri, + ) { + this.disposables = [ + vscode.window.registerWebviewViewProvider('vitest.webviewSettings', this), + ] + } + + resolveWebviewView(webviewView: vscode.WebviewView, _context: vscode.WebviewViewResolveContext, _token: vscode.CancellationToken): Thenable | void { + this.view = webviewView + + webviewView.webview.options = { + enableScripts: true, + localResourceRoots: [this.extensionUri], + } + + webviewView.webview.html = createHtmlView(webviewView.webview) + + this.disposables.push( + // when we get the message from the view, process it + webviewView.webview.onDidReceiveMessage((message) => { + if (message.method === 'toggle') { + const settings = vscode.workspace.getConfiguration('vitest') + settings.update(message.args.setting, !settings.get(message.args.setting)) + } + }), + // when the user changes the configuration manually, update the view + vscode.workspace.onDidChangeConfiguration((e) => { + if (e.affectsConfiguration('vitest.previewBrowser')) { + this.updateSettings() + } + }), + // when the weview is opened, make sure it's up to date + webviewView.onDidChangeVisibility(() => { + if (!webviewView.visible) + return + this.updateSettings() + }), + ) + + this.updateSettings() + } + + updateSettings() { + this.view?.webview.postMessage({ + method: 'settings', + args: { + settings: getConfig(), + }, + }) + } + + dispose() { + this.disposables.forEach(d => d.dispose()) + this.disposables = [] + } +} + +// based on +// https://github.com/microsoft/playwright-vscode/blob/4454e6876bfde1b4a8570dbaeca1ad14e8cd37c8/src/settingsView.ts +function createHtmlView(webview: vscode.Webview) { + // + const nonce = nanoid() + return ` + + + + + + + Vitest + + +
+
+ +
+
+ + + + ` +}