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

Interactive documentation for side panel #351

Closed
wants to merge 9 commits into from
Closed
46 changes: 45 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,18 @@
"command": "vscode-edge-devtools-view.viewChangelog",
"category": "Microsoft Edge Tools",
"title": "View Changelog"
},
{
"command": "vscode-edge-devtools-view.configureLaunchJson",
"category": "Microsoft Edge Tools",
"enablement": "titleCommandsRegistered",
"title": "Configure launch.json file"
},
{
"command": "vscode-edge-devtools-view.launchProject",
"category": "Microsoft Edge Tools",
"enablement": "titleCommandsRegistered",
"title": "Launch project"
}
],
"configuration": {
Expand Down Expand Up @@ -516,7 +528,39 @@
"name": "Targets"
}
]
}
},
"viewsWelcome": [
{
"view": "vscode-edge-devtools-view.targets",
"contents": "Launch an instance of Microsoft Edge to begin inspecting and modifying webpages.\n[Launch Instance](command:vscode-edge-devtools-view.launch)",
"when": "titleCommandsRegistered && launchJsonStatus != Supported"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should show all the content for the empty target list immediately and not wait on the titleCommandsRegistered flag. We can disable the buttons that actually launch commands until they're ready with the enablement flag when the commands are registered.

},
{
"view": "vscode-edge-devtools-view.targets",
"contents": "To customize your launch experience, [open a folder](command:vscode.openFolder) and create a launch.json file.",
"when": "titleCommandsRegistered && workbenchState == empty"
},
{
"view": "vscode-edge-devtools-view.targets",
"contents": "Customize your launch experience by adding a launch.json file to your project.\n[Generate launch.json](command:vscode-edge-devtools-view.configureLaunchJson)",
"when": "titleCommandsRegistered && workbenchState != empty && launchJsonStatus == None"
},
{
"view": "vscode-edge-devtools-view.targets",
"contents": "Customize your launch experience by adding a debug configuration to your launch.json file.\n[Configure launch.json](command:vscode-edge-devtools-view.configureLaunchJson)",
"when": "titleCommandsRegistered && launchJsonStatus == Unsupported"
},
{
"view": "vscode-edge-devtools-view.targets",
"contents": "Launch an instance of Microsoft Edge to begin inspecting and modifying your site.\n[Launch Project](command:vscode-edge-devtools-view.launchProject)",
"when": "titleCommandsRegistered && launchJsonStatus == Supported"
},
{
"view": "vscode-edge-devtools-view.targets",
"contents": "If you have any questions or want to learn more, check the [docs on GitHub](https://github.com/microsoft/vscode-edge-devtools/blob/master/README.md)",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will add a period at the end of this sentence when I go to address feedback

"when": "titleCommandsRegistered"
}
]
},
"jest": {
"transform": {
Expand Down
10 changes: 8 additions & 2 deletions src/extension.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ describe("extension", () => {
getRemoteEndpointSettings: jest.fn(),
getRuntimeConfig: jest.fn(),
removeTrailingSlash: jest.fn(removeTrailingSlash),
getLaunchJson: jest.fn(),
};
jest.doMock("./utils", () => mockUtils);
jest.doMock("./launchDebugProvider");
Expand Down Expand Up @@ -72,8 +73,8 @@ describe("extension", () => {
// Activation should add the commands as subscriptions on the context
newExtension.activate(context);

expect(context.subscriptions.length).toBe(10);
expect(commandMock).toHaveBeenCalledTimes(9);
expect(context.subscriptions.length).toBe(12);
expect(commandMock).toHaveBeenCalledTimes(11);
expect(commandMock)
.toHaveBeenNthCalledWith(1, `${SETTINGS_STORE_NAME}.attach`, expect.any(Function));
expect(commandMock)
Expand All @@ -92,6 +93,10 @@ describe("extension", () => {
.toHaveBeenNthCalledWith(8, `${SETTINGS_VIEW_NAME}.close-instance`, expect.any(Function));
expect(commandMock)
.toHaveBeenNthCalledWith(9, `${SETTINGS_VIEW_NAME}.copyItem`, expect.any(Function));
expect(commandMock)
.toHaveBeenNthCalledWith(10, `${SETTINGS_VIEW_NAME}.configureLaunchJson`, expect.any(Function));
expect(commandMock)
.toHaveBeenNthCalledWith(11, `${SETTINGS_VIEW_NAME}.launchProject`, expect.any(Function));
expect(mockRegisterTree)
.toHaveBeenNthCalledWith(1, `${SETTINGS_VIEW_NAME}.targets`, expect.any(Object));
});
Expand Down Expand Up @@ -385,6 +390,7 @@ describe("extension", () => {
launchBrowser: jest.fn().mockResolvedValue(fakeBrowser),
openNewTab: jest.fn().mockResolvedValue(null),
removeTrailingSlash: jest.fn(removeTrailingSlash),
getLaunchJson: jest.fn(),
};

mockPanel = {
Expand Down
21 changes: 21 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import {
getListOfTargets,
getRemoteEndpointSettings,
getRuntimeConfig,
getLaunchJson,
configureLaunchJson,
IRemoteTargetJson,
IUserConfig,
launchBrowser,
Expand All @@ -27,12 +29,16 @@ import {

let telemetryReporter: Readonly<TelemetryReporter>;
let browserInstance: Browser;
let launchConfig: vscode.DebugConfiguration | null;

export function activate(context: vscode.ExtensionContext) {
if (!telemetryReporter) {
telemetryReporter = createTelemetryReporter(context);
}

// Check if launch.json exists and has supported config to populate side pane welcome message
launchConfig = getLaunchJson();

context.subscriptions.push(vscode.commands.registerCommand(`${SETTINGS_STORE_NAME}.attach`, async () => {
attach(context);
}));
Expand Down Expand Up @@ -112,6 +118,21 @@ export function activate(context: vscode.ExtensionContext) {
context.subscriptions.push(vscode.commands.registerCommand(
`${SETTINGS_VIEW_NAME}.copyItem`,
(target: CDPTarget) => vscode.env.clipboard.writeText(target.tooltip)));
context.subscriptions.push(vscode.commands.registerCommand(
`${SETTINGS_VIEW_NAME}.configureLaunchJson`,
() => {
configureLaunchJson();
launchConfig = getLaunchJson();
}));
context.subscriptions.push(vscode.commands.registerCommand(
`${SETTINGS_VIEW_NAME}.launchProject`,
() => {
launchConfig = getLaunchJson();
if (vscode.workspace.workspaceFolders && launchConfig) {
vscode.debug.startDebugging(vscode.workspace.workspaceFolders[0], launchConfig);
cdpTargetsProvider.refresh();
}
}));
vscode.commands.executeCommand('setContext', 'titleCommandsRegistered', true);
}

Expand Down
8 changes: 2 additions & 6 deletions src/launchDebugProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as vscode from "vscode";
import TelemetryReporter from "vscode-extension-telemetry";
import {
IUserConfig,
providedDebugConfig,
SETTINGS_DEFAULT_ATTACH_INTERVAL,
SETTINGS_DEFAULT_EDGE_DEBUGGER_PORT,
SETTINGS_STORE_NAME,
Expand Down Expand Up @@ -40,12 +41,7 @@ export default class LaunchDebugProvider implements vscode.DebugConfigurationPro
public provideDebugConfigurations(
folder: vscode.WorkspaceFolder | undefined,
token?: vscode.CancellationToken): vscode.ProviderResult<vscode.DebugConfiguration[]> {
return Promise.resolve([{
name: "Launch Microsoft Edge and open the Edge DevTools",
request: "launch",
type: `${SETTINGS_STORE_NAME}.debug`,
url: "http://localhost:8080",
}]);
return Promise.resolve([providedDebugConfig]);
}

public resolveDebugConfiguration(
Expand Down
73 changes: 73 additions & 0 deletions src/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,79 @@ describe("utils", () => {
});
});

describe('getLaunchJson', () => {
let fse: Mocked<typeof import("fs-extra")>;

beforeEach(async () => {
jest.doMock("fs-extra");
jest.resetModules();
utils = await import("./utils");
fse = jest.requireMock("fs-extra");
});

it('updates launchJsonStatus with "None" when there is no folder open', async () => {
const vscodeMock = await jest.requireMock("vscode");
vscodeMock.workspace.workspaceFolders = null;
utils.getLaunchJson();
expect(utils.getLaunchJson()).toEqual(null);
expect(vscodeMock.commands.executeCommand).toBeCalledWith('setContext', 'launchJsonStatus', 'None');
});

it('updates launchJsonStatus with "None" when launch.json does not exist', async () => {
const vscodeMock = await jest.requireMock("vscode");
fse.pathExistsSync.mockImplementation(() => false);
utils.getLaunchJson();
expect(utils.getLaunchJson()).toEqual(null);
expect(vscodeMock.commands.executeCommand).toBeCalledWith('setContext', 'launchJsonStatus', 'None');
});

it('updates launchJsonStatus with "Unsupported" when there is no supported debug config', async () => {
const vscodeMock = await jest.requireMock("vscode");
fse.pathExistsSync.mockImplementation(() => true);
vscodeMock.workspace.getConfiguration.mockImplementation(() => {
return {
get: (name: string) => [{type: ''}]
}
});
expect(utils.getLaunchJson()).toEqual(null);
expect(vscodeMock.commands.executeCommand).toBeCalledWith('setContext', 'launchJsonStatus', 'Unsupported');
});

it('returns a supported debug config when one exists', async () => {
const vscodeMock = await jest.requireMock("vscode");
fse.pathExistsSync.mockImplementation(() => true);
vscodeMock.workspace.getConfiguration.mockImplementation(() => {
return {
get: (name: string) => [{type: 'vscode-edge-devtools.debug'}]
}
});
expect(utils.getLaunchJson()).toEqual({type: 'vscode-edge-devtools.debug'});
expect(vscodeMock.commands.executeCommand).toBeCalledWith('setContext', 'launchJsonStatus', 'Supported');
});
});

describe('configureLaunchJson', () => {
jest.resetModules();

it('adds a debug config to launch.json', async () => {
utils = await import("./utils");
const vscodeMock = await jest.requireMock("vscode");
vscodeMock.Uri.joinPath = jest.fn();
vscodeMock.WorkspaceConfiguration = {
update: jest.fn((name: string, value: any) => {}),
};
vscodeMock.workspace.getConfiguration.mockImplementation(() => {
return {
get: jest.fn((name: string) => []),
update: vscodeMock.WorkspaceConfiguration.update,

}
});
utils.configureLaunchJson();
expect(vscodeMock.WorkspaceConfiguration.update).toBeCalledWith('configurations', expect.arrayContaining([expect.any(Object)]));
});
});

describe("launchBrowser", () => {
beforeEach(async () => {
jest.mock("puppeteer-core", () => {
Expand Down
61 changes: 61 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,12 @@ export const SETTINGS_DEFAULT_SOURCE_MAPS = true;
export const SETTINGS_DEFAULT_EDGE_DEBUGGER_PORT = 2015;
export const SETTINGS_DEFAULT_ATTACH_TIMEOUT = 10000;
export const SETTINGS_DEFAULT_ATTACH_INTERVAL = 200;
export const providedDebugConfig: vscode.DebugConfiguration = {
name: "Launch Microsoft Edge and open the Edge DevTools",
request: "launch",
type: `${SETTINGS_STORE_NAME}.debug`,
url: "http://localhost:8080",
};

const WIN_APP_DATA = process.env.LOCALAPPDATA || "/";
const msEdgeBrowserMapping: Map<BrowserFlavor, IBrowserPath> = new Map();
Expand Down Expand Up @@ -284,6 +290,61 @@ export async function getBrowserPath(config: Partial<IUserConfig> = {}): Promise
}
}

/**
* Gets a supported debug config and updates the status of the launch.json file associated with the current workspace
* @returns {vscode.DebugConfiguration | null}
*/
export function getLaunchJson(): vscode.DebugConfiguration | null {
// Check if there is a folder open
if (!vscode.workspace.workspaceFolders) {
vscode.commands.executeCommand('setContext', 'launchJsonStatus', "None");
return null;
}

// Check if there's a launch.json file
const workspaceUri = vscode.workspace.workspaceFolders[0].uri;
const filePath = `${workspaceUri.fsPath}/.vscode/launch.json`;
if (fse.pathExistsSync(filePath)) {
// Check if there is a supported debug config
const configs = vscode.workspace.getConfiguration('launch', workspaceUri).get('configurations') as vscode.DebugConfiguration[];
for (const config of configs) {
if (config.type === 'vscode-edge-devtools.debug' || config.type === 'msedge' || config.type === 'edge') {
vscode.commands.executeCommand('setContext', 'launchJsonStatus', "Supported");
return config;
}
}
vscode.commands.executeCommand('setContext', 'launchJsonStatus', "Unsupported");
return null;
} else {
vscode.commands.executeCommand('setContext', 'launchJsonStatus', "None");
return null;
}
}

/**
* Add a template for a supported debug configuration to launch.json
* @returns {void}
*/
export function configureLaunchJson(): void {
if (!vscode.workspace.workspaceFolders)
return;

// Create ./.vscode/launch.json if it doesn't already exist
const workspaceUri = vscode.workspace.workspaceFolders[0].uri;
fse.ensureFileSync(`${workspaceUri.fsPath}/.vscode/launch.json`);

// Append a supported debug config to their list of configurations
const launchJson = vscode.workspace.getConfiguration('launch', workspaceUri);
let configs = launchJson.get('configurations') as vscode.DebugConfiguration[];
let configWithInstruction = {...providedDebugConfig};
configWithInstruction.url += ' **Replace with your website url before launching**';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be a cleaner experience if we instead default to the new startpage in the generated launch.json, and leave a comment after the url that contains this text. That way, the generated launch.json is valid without any edits?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would depend on #350 . Or we could default to the localhost link for now and I could update my PR if this lands first

configs.push(configWithInstruction);

// Update launch.json with new configuration list and open in editor
launchJson.update('configurations', configs);
vscode.commands.executeCommand('vscode.open', vscode.Uri.joinPath(workspaceUri, '/.vscode/launch.json'));
}

/**
* Launch the specified browser with remote debugging enabled
*
Expand Down