Skip to content
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

feat: add a button to toggle the browser preview in browser mode #495

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
15 changes: 15 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
3 changes: 3 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,13 @@ export function getConfig(workspaceFolder?: WorkspaceFolder) {
const shellType = get<'child_process' | 'terminal'>('shellType', 'child_process')
const nodeExecArgs = get<string[] | undefined>('nodeExecArgs')

const previewBrowser = get<boolean>('previewBrowser', false)

return {
env: get<null | Record<string, string>>('nodeEnv', null),
debugExclude: get<string[]>('debugExclude', []),
filesWatcherInclude,
previewBrowser,
terminalShellArgs,
terminalShellPath,
shellType,
Expand Down
7 changes: 5 additions & 2 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
Expand All @@ -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')
Expand Down Expand Up @@ -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)))
Expand Down Expand Up @@ -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
Expand Down
117 changes: 117 additions & 0 deletions src/settingsWebview.ts
Original file line number Diff line number Diff line change
@@ -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> | 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) {
// <link href="${styleUri}" rel="stylesheet">
const nonce = nanoid()
return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src ${webview.cspSource}; script-src 'nonce-${nonce}';">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vitest</title>
</head>
<body>
<div class="list">
<div>
<label title="${vscode.l10n.t('Show the browser when running tests in the Browser Mode. This will disable parallel execution.')}">
<input type="checkbox" data-setting="previewBrowser"></input>
${vscode.l10n.t('Show browser')}
</label>
</div>
</div>
<script nonce="${nonce}">
const vscode = acquireVsCodeApi();
for (const input of document.querySelectorAll('input[type=checkbox]')) {
console.log('input', input)
input.addEventListener('change', event => {
vscode.postMessage({ method: 'toggle', args: { setting: event.target.dataset.setting } });
});
}
window.addEventListener('message', event => {
const { method, args } = event.data;
if (method === 'settings') {
for (const [key, value] of Object.entries(args.settings)) {
const input = document.querySelector('input[data-setting=' + key + ']');
console.log('input', input, key, value)
if (!input)
continue;
if (typeof value === 'boolean')
input.checked = value;
else
input.value = value;
}
}
})
</script>
</body>
</html>
`
}
Loading