Skip to content

Commit

Permalink
User/elormcoch/wsl extension fix (#1804)
Browse files Browse the repository at this point in the history
* adapt launch and debug to remote environment

* fix linux ci failure

* Use uri authority in launch args for remote wsl context

* Add tests for launch in remote and non-remote contexts

* Update tests

* Rename parameter to forceHeadless
  • Loading branch information
ElormCoch committed Jan 25, 2024
1 parent d50d767 commit 5afc13a
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 15 deletions.
48 changes: 38 additions & 10 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,20 +239,15 @@ export function activate(context: vscode.ExtensionContext): void {
void setCSSMirrorContentEnabled(context, !cssMirrorContent);
}));

context.subscriptions.push(vscode.commands.registerCommand(`${SETTINGS_VIEW_NAME}.launchHtml`, (fileUri: vscode.Uri): void => {
context.subscriptions.push(vscode.commands.registerCommand(`${SETTINGS_VIEW_NAME}.launchHtml`, async (fileUri: vscode.Uri): Promise<void> => {
telemetryReporter.sendTelemetryEvent('contextMenu/launchHtml');
const edgeDebugConfig = providedHeadlessDebugConfig;
const devToolsAttachConfig = providedLaunchDevToolsConfig;
edgeDebugConfig.url = `file://${fileUri.fsPath}`;
devToolsAttachConfig.url = `file://${fileUri.fsPath}`;
void vscode.debug.startDebugging(undefined, edgeDebugConfig).then(() => vscode.debug.startDebugging(undefined, devToolsAttachConfig));
await launchHtml(fileUri);
}));

context.subscriptions.push(vscode.commands.registerCommand(`${SETTINGS_VIEW_NAME}.launchScreencast`, (fileUri: vscode.Uri): void => {

context.subscriptions.push(vscode.commands.registerCommand(`${SETTINGS_VIEW_NAME}.launchScreencast`, async (fileUri: vscode.Uri): Promise<void> => {
telemetryReporter.sendTelemetryEvent('contextMenu/launchScreencast');
const edgeDebugConfig = providedHeadlessDebugConfig;
edgeDebugConfig.url = `file://${fileUri.fsPath}`;
void vscode.debug.startDebugging(undefined, edgeDebugConfig).then(() => attach(context, fileUri.fsPath, undefined, true, true));
await launchScreencast(context, fileUri);
}));

void vscode.commands.executeCommand('setContext', 'titleCommandsRegistered', true);
Expand All @@ -275,6 +270,39 @@ export function activate(context: vscode.ExtensionContext): void {
});
}

export async function launchHtml(fileUri: vscode.Uri): Promise<void> {
const edgeDebugConfig = providedHeadlessDebugConfig;
const devToolsAttachConfig = providedLaunchDevToolsConfig;
if (!vscode.env.remoteName) {
edgeDebugConfig.url = `file://${fileUri.fsPath}`;
devToolsAttachConfig.url = `file://${fileUri.fsPath}`;
void vscode.debug.startDebugging(undefined, edgeDebugConfig).then(() => vscode.debug.startDebugging(undefined, devToolsAttachConfig));
} else {
// Parse the filename from the remoteName, file authority and path e.g. file://wsl.localhost/ubuntu-20.04/test/index.html
const url = `file://${vscode.env.remoteName}.localhost/${fileUri.authority.split('+')[1]}/${fileUri.fsPath.replace(/\\/g, '/')}`;
edgeDebugConfig.url = url;
devToolsAttachConfig.url = url;
const { port, userDataDir } = getRemoteEndpointSettings();
const browserPath = await getBrowserPath();
await launchBrowser(browserPath, port, url, userDataDir, /** headless */ true).then(() => vscode.debug.startDebugging(undefined, devToolsAttachConfig));
}
}

export async function launchScreencast(context: vscode.ExtensionContext, fileUri: vscode.Uri): Promise<void> {
const edgeDebugConfig = providedHeadlessDebugConfig;
if (!vscode.env.remoteName) {
edgeDebugConfig.url = `file://${fileUri.fsPath}`;
void vscode.debug.startDebugging(undefined, edgeDebugConfig).then(() => attach(context, fileUri.fsPath, undefined, true, true));
} else {
// Parse the filename from the remoteName, file authority and path e.g. file://wsl.localhost/ubuntu-20.04/test/index.html
const url = `file://${vscode.env.remoteName}.localhost/${fileUri.authority.split('+')[1]}/${fileUri.fsPath.replace(/\\/g, '/')}`;
edgeDebugConfig.url = url;
const { port, userDataDir } = getRemoteEndpointSettings();
const browserPath = await getBrowserPath();
await launchBrowser(browserPath, port, url, userDataDir, /** headless */ true).then(() => attach(context, url, undefined, true, true));
}
}

function startWebhint(context: vscode.ExtensionContext): void {
const args = [context.globalStoragePath, languageServerName];
const module = context.asAbsolutePath('node_modules/vscode-webhint/dist/src/server.js');
Expand Down
5 changes: 3 additions & 2 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -390,16 +390,17 @@ export async function getBrowserPath(config: Partial<IUserConfig> = {}): Promise
* @param port The port on which to enable remote debugging
* @param targetUrl The url of the page to open
* @param userDataDir The user data directory for the launched instance
* @param forceHeadless This force overrides the --headless arg for browser launch
*/
export async function launchBrowser(browserPath: string, port: number, targetUrl: string, userDataDir?: string): Promise<puppeteer.Browser> {
export async function launchBrowser(browserPath: string, port: number, targetUrl: string, userDataDir?: string, forceHeadless?: boolean): Promise<puppeteer.Browser> {
const args = [
'--no-first-run',
'--no-default-browser-check',
`--remote-debugging-port=${port}`,
targetUrl,
];

const headless: boolean = isHeadlessEnabled();
const headless: boolean = forceHeadless ?? isHeadlessEnabled();

let browserArgs: string[] = getBrowserArgs();
browserArgs = browserArgs.filter(arg => !arg.startsWith('--remote-debugging-port') && arg !== targetUrl);
Expand Down
62 changes: 60 additions & 2 deletions test/extension.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

import { ExtensionContext } from "vscode";
import { ExtensionContext, Uri} from "vscode";
import TelemetryReporter from "vscode-extension-telemetry";
import { createFakeExtensionContext, createFakeTelemetryReporter, createFakeVSCode, Mocked } from "./helpers/helpers";
import {
Expand Down Expand Up @@ -396,6 +396,8 @@ describe("extension", () => {
let mockReporter: Mocked<Readonly<TelemetryReporter>>;
let mockUtils: Partial<Mocked<typeof import("../src/utils")>>;
let mockPanel: Partial<Mocked<typeof import("../src/devtoolsPanel")>>;
let startDebuggingMock: jest.Mock;
let mockVSCode: any;

beforeEach(() => {
mockReporter = createFakeTelemetryReporter();
Expand All @@ -409,6 +411,7 @@ describe("extension", () => {
port: "port",
timeout: 10000,
useHttps: false,
userDataDir: "profile"
}),
getSupportedStaticAnalysisFileTypes: jest.fn(),
getRuntimeConfig: jest.fn().mockReturnValue(fakeRuntimeConfig),
Expand All @@ -428,13 +431,68 @@ describe("extension", () => {
createOrShow: jest.fn(),
} as any,
};
mockVSCode = createFakeVSCode();
startDebuggingMock = mockVSCode.debug.startDebugging;

jest.doMock("vscode", () => createFakeVSCode(), { virtual: true });
jest.doMock("vscode", () => mockVSCode, { virtual: true });
jest.doMock("../src/utils", () => mockUtils);
jest.doMock("../src/devtoolsPanel", () => mockPanel);
jest.resetModules();
});


it("can launch html files in remote (wsl) context", async () => {
const expectedRemoteName = 'wsl';
const testFileUri = {
scheme: 'vscode-remote',
authority: 'wsl+ubuntu-20.04',
fsPath: 'test/path.html',
query: '',
fragment: ''
} as Uri;

mockVSCode.env.remoteName = expectedRemoteName;

const expectedUrl = `file://${expectedRemoteName}.localhost/ubuntu-20.04/test/path.html`;

const newExtension = await import("../src/extension");
await newExtension.launchHtml(testFileUri);

expect(mockUtils.getRemoteEndpointSettings).toHaveBeenCalled()
expect(mockUtils.getBrowserPath).toHaveBeenCalled();
expect(mockUtils.launchBrowser).toHaveBeenCalledWith(
expect.any(String) /** browserPath */,
expect.any(String) /** port */,
expectedUrl /** targetUrl */,
expect.any(String) /** userDataDir */,
expect.any(Boolean) /** headlessOverride */
);
expect(startDebuggingMock).toHaveBeenCalledWith(undefined, expect.objectContaining({
url: expectedUrl
}));
});

it("can launch html files in non-remote contexts", async () => {
mockVSCode.env.remoteName = undefined;
const testFileUri = {
scheme: 'file',
authority: '',
fsPath: 'test/path.html',
query: '',
fragment: ''
} as Uri;
const expectedUrl = `file://test/path.html`;

const newExtension = await import("../src/extension");
await newExtension.launchHtml(testFileUri);
expect(startDebuggingMock).toHaveBeenNthCalledWith(1, undefined, expect.objectContaining({
url: expectedUrl
}));
expect(startDebuggingMock).toHaveBeenNthCalledWith(2, undefined, expect.objectContaining({
url: expectedUrl
}));
});

it("calls launch on launch command", async () => {
const vscode = jest.requireMock("vscode");
const context = createFakeExtensionContext();
Expand Down
4 changes: 3 additions & 1 deletion test/helpers/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ export function createFakeVSCode() {
activeDebugSession: {
id: 'vscode-session-debug-id',
name: 'someName',
}
},
startDebugging: jest.fn().mockResolvedValue(true),
},
extensions: {
getExtension: jest.fn().mockReturnValue({
Expand All @@ -73,6 +74,7 @@ export function createFakeVSCode() {
env: {
clipboard: { writeText: jest.fn() },
machineId: "someValue.machineId",
remoteName: '',
},
languages: {
createDiagnosticCollection: jest.fn(),
Expand Down

0 comments on commit 5afc13a

Please sign in to comment.