Skip to content

Commit

Permalink
adding verbose logging
Browse files Browse the repository at this point in the history
  • Loading branch information
connectdotz committed Jan 30, 2021
1 parent 2f1ab05 commit 999b457
Show file tree
Hide file tree
Showing 14 changed files with 288 additions and 199 deletions.
35 changes: 19 additions & 16 deletions setup-wizard.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

This is an interactive tool to help users set up vscode-jest extension if the default configuration is not sufficient.

_(As in v4, wizard is released as a beta product. We appreciate you trying out and help improving it so it can be more useful for the community 👍)_
_(The setup wizard is released as a beta product in v4. Thank you for trying it out! 👍 Please don't hesitate to make suggestion or file issues so we can quickly improve and make it more useful for the community.)_


---
Expand All @@ -20,11 +20,11 @@ _(As in v4, wizard is released as a beta product. We appreciate you trying out a

It helps users to set up the essential configurations of the extension via a simple UI. While the extension provides default configurations that work for the common standard environments, such as CRA and plain jest, the more sophisticated projects are most likely needed to customize the extension for their environments. And this is where the setup wizard comes in.

The wizard asks questions and collects answers to update user's workspace `settings.json` and `launch.json` accordingly ( [How does it work ?](#how-does-it-work)). It works for single and multi-root workspaces. It creates an OUTPUT channel `vscode-jest Setup` with progress, instructions and status, which also will be handy for reporting and diagnosis issues.
The wizard asks questions and collects answers to update user's workspace `settings.json` and `launch.json` accordingly ( [How does it work ?](#how-does-it-work)). It works for single and multi-root workspaces. It creates an OUTPUT channel `"vscode-jest Setup"` showing progress, and tips to make wizard easier to use and diagnose should there be an issue.

Users can run the wizard any time they want ([How to run it ?](how-to-run-it)) and safely abort if desired.

The wizard tries its best to create accurate configurations but it will not be able to cover all the use cases out there. However, it always strikes for transparency, and shows where and what the configuration will be updated so users can easily modify it if needed.
The wizard tries its best to create accurate configurations but it will not be able to cover all the use cases out there. However, it always strikes for transparency, and shows where and what the configuration will be updated so users can easily modify it later manually if needed.

_(Note: the wizard is not to set up [jest](https://jestjs.io) itself. Actually, a working jest environment (such as you can run jest tests in terminal) is a prerequisite of running `vscode-jest` extension.)_
## How to run it
Expand All @@ -45,7 +45,14 @@ The extension start jest tests process on behave of the users by issuing the sam

Please be aware that all relative paths in the settings are resolved against the `rootPath`, which by default is the current workspace folder unless you customize it with `"jest.rootPath"`.

This command line is required to configure the debug config below.

While users can pass any jest CLI options in the `"jest.jestCommandLine"`, it is recommended NOT to pass the following:
- the watch options (--watch, --watchAll): the extension will append watch flag when needed.
- the coverage option (--coverage): user can easily toggle on/off coverage via command so no need to add it on the commandLine.

Because the extension appends additional options to this commandLine at run time, please make sure these additional options can be passed through, for example, if your command-line is `"npm test"`, make sure you add `"--"` at the end to pass through the additional options: `"npm test --"`

**Please note, `"jest.jestCommandLine"` setting is required to configure the debug config below.**

### Debug Config
When clicked on the debug codeLens, the extension will look for a debug config named `"vscode-jest-tests"`, and append the additional arguments (such as `--testNamePattern`) when launching the debugger.
Expand All @@ -54,9 +61,9 @@ If there is no existing `"jest.jestCommandLine"`, it will suggest to set one up

The wizard will examine the `launch.json` for existing config. If found, users can choose to use it as it is, replace (rename the old one and generate a new one) or manually editing it; if not found, wizard will try to [generate](#note-2) a new one.

The debug config is saved in `launch.json` in workspace folder and shown at the end of the setup for review/adjustment. If you choose "replace" the existing config, the old configure will be renamed to `vscode-jest-tests-xxxxx` for reference purpose only, which can be safely deleted if you don't need it.
The debug config is saved in `launch.json` in workspace folder and shown at the end of the setup for review or adjustment. If the user chooses to "replace" the existing config, the old configure will be renamed to `vscode-jest-tests-xxxxx` for reference purpose only, which can be safely deleted if not needed.

The generated config probably work fine for most projects, but could require further adjustment for some other projects including but not limited to
The generated config probably work fine for most projects, but could require further adjustment for projects including but not limited to the following:
- projects use different jest config between debug and regular test run
- projects with [platform specific properties](#note-3).

Expand Down Expand Up @@ -87,7 +94,7 @@ Check out [here](#note-4) if you are having problem running vscode-jest debug co
- obtain a debug template from `DebugConfigurationProvider`
- merge the jest command and arguments with the template.
- if the command is `npm` or `yarn` it updates `runtimeExecutable` property; otherwise updates `program`
- the arguments will be added to the `args` property, plus jest debug specific flag such as `--runInBand`.
- the arguments will be added to the `args` property, plus jest debug specific flags such as `--runInBand`.
- update `cwd` property with either `jest.rootPath` if defined, otherwise the vscode variable `"${workspaceFolder}"`


Expand All @@ -113,19 +120,15 @@ Check out [here](#note-4) if you are having problem running vscode-jest debug co
]
```
See more details and examples in [vscode: platform specific properties](https://code.visualstudio.com/docs/editor/debugging#_platformspecific-properties).

The wizard can preserve the existing platform specific properties while merging the new `jest.jestCommandLine` but does not guarantee they are consistent. Therefore, it is advise to always double check the debug config upon `jest.jestCommandLine` changes.


- <a id="note-4">**vscode-jest debug codeLens failed, now what?**</a>

If your regular jest run was fine but you can't debug the test with debug codeLens after running wizard. There should be some error message in your terminal that might help you pinpoint the culprit. There are many information online about how to setup vscode debug config for specific environments/frameworks, you might also find the following helpful:
If your regular jest run was fine but you can't debug the test with debug codeLens after running wizard. There should be some error message in your terminal that might help you pinpoint the culprit.

There are many information online about how to setup vscode debug config for specific environments/frameworks, you might find the following helpful:
- [vscode debug config properties](https://code.visualstudio.com/docs/nodejs/nodejs-debugging#_launch-configuration-properties)
- [Launch configurations for common scenarios](https://code.visualstudio.com/docs/nodejs/nodejs-debugging#_launch-configurations-for-common-scenarios)
- [vscode-recipes for debug jest tests](https://github.com/microsoft/vscode-recipes/tree/master/debugging-jest-tests)

If you think your use case is quite common, feel free to create a discussion/issue for enhancing the wizard or contribute your example debug config.





While you can manually correct the debug config and move on, if you think your use case is actually quite common, feel free to create a discussion/issue so we might be able to enhance the wizard or include your example config to help others.
1 change: 1 addition & 0 deletions src/JestExt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ export class JestExt {
vscode.commands.executeCommand(`${extensionName}.setup-extension`, {
workspace: this.workspaceFolder,
taskId,
verbose: this.jestWorkspace.debug,
}),
};
}
Expand Down
11 changes: 3 additions & 8 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ import { extensionName } from './appGlobals';
import { statusBar } from './StatusBar';
import { ExtensionManager, getExtensionWindowSettings } from './extensionManager';
import { registerSnapshotCodeLens, registerSnapshotPreview } from './SnapshotCodeLens';
import { startWizard } from './setup-wizard';
import { startWizard, StartWizardOptions } from './setup-wizard';
import { DebugTestIdentifier } from './DebugCodeLens';
import { WizardTaskId } from './setup-wizard/start-wizard';

let extensionManager: ExtensionManager;

Expand Down Expand Up @@ -42,12 +41,8 @@ export function activate(context: vscode.ExtensionContext): void {
),
vscode.commands.registerCommand(
`${extensionName}.setup-extension`,
(options?: { workspace: vscode.WorkspaceFolder; taskId: WizardTaskId }) =>
startWizard(
extensionManager.debugConfigurationProvider,
options?.workspace,
options?.taskId
)
(options: StartWizardOptions = { verbose: true }) =>
startWizard(extensionManager.debugConfigurationProvider, options)
),
vscode.commands.registerCommand(
`${extensionName}.run-test`,
Expand Down
2 changes: 1 addition & 1 deletion src/setup-wizard/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { startWizard, WizardTaskId } from './start-wizard';
export { startWizard, StartWizardOptions, WizardTaskId } from './start-wizard';
64 changes: 34 additions & 30 deletions src/setup-wizard/start-wizard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,39 +9,30 @@ import {
import { jsonOut, actionItem, showActionMenu } from './wizard-helper';
import { setupJestCmdLine, setupJestDebug } from './tasks';

export const createWizardContext = (
workspace: vscode.WorkspaceFolder,
debugConfigProvider: vscode.DebugConfigurationProvider,
message: (msg: string, section?: string) => void
): WizardContext => {
return {
debugConfigProvider,
workspace,
message,
};
};

export const StartWizardActionId = {
cmdLine: 0,
debugConfig: 1,
exit: 2,
};
export type WizardTaskId = 'cmdLine' | 'debugConfig';
const TaskActionMap: { [key in WizardTaskId]: number } = {
['cmdLine']: StartWizardActionId.cmdLine,
['debugConfig']: StartWizardActionId.debugConfig,
};

export const WizardTasks: { [key in WizardTaskId]: SetupTask } = {
['cmdLine']: setupJestCmdLine,
['debugConfig']: setupJestDebug,
// wizard tasks - right now only 2, could easily add more
export type WizardTaskId = 'cmdLine' | 'debugConfig';
export const WizardTasks: { [key in WizardTaskId]: { task: SetupTask; actionId: number } } = {
['cmdLine']: { task: setupJestCmdLine, actionId: StartWizardActionId.cmdLine },
['debugConfig']: { task: setupJestDebug, actionId: StartWizardActionId.debugConfig },
};

export interface StartWizardOptions {
workspace?: vscode.WorkspaceFolder;
taskId?: WizardTaskId;
verbose?: boolean;
}
export const startWizard = (
debugConfigProvider: vscode.DebugConfigurationProvider,
ws?: vscode.WorkspaceFolder,
taskId?: WizardTaskId
options: StartWizardOptions = {}
): Promise<WizardStatus> => {
const { workspace, taskId, verbose } = options;

const _output = vscode.window.createOutputChannel('vscode-jest Setup');

const dispose = (): void => {
Expand All @@ -50,14 +41,25 @@ export const startWizard = (

const message = (msg: string, section?: string): void => {
if (section) {
_output.appendLine(`\n===== ${section} =====\n`);
const m = `\n===== ${section} =====\n`;
_output.appendLine(m);
if (verbose) {
console.log(`<SetupWizard> ${m}`);
}
}
if (verbose) {
console.log(`<SetupWizard> ${msg}`);
}
_output.appendLine(msg);
_output.show(true);
};

const runTask = async (context: WizardContext, taskId: WizardTaskId): Promise<WizardStatus> =>
WizardTasks[taskId](context);
const runTask = async (context: WizardContext, taskId: WizardTaskId): Promise<WizardStatus> => {
message(`starting ${taskId} task...`);
const result = await WizardTasks[taskId].task(context);
message(`${taskId} task returns ${result}`);
return result;
};

const showMainMenu = async (context: WizardContext): Promise<WizardStatus> => {
const menuItems: ActionableMenuItem<WizardStatus>[] = [
Expand All @@ -79,12 +81,13 @@ export const startWizard = (
];

let result: WizardStatus;
let selectItemIdx = menuItems.findIndex((item) => item.id === TaskActionMap[taskId]);
let selectItemIdx = menuItems.findIndex((item) => item.id === WizardTasks[taskId]?.actionId);
do {
result = await showActionMenu(menuItems, {
title: 'vscode-jest Setup Wizard',
placeholder: 'select a set up action below',
selectItemIdx,
verbose,
});
selectItemIdx = undefined;
} while (result !== 'exit' && result !== 'error');
Expand All @@ -108,15 +111,16 @@ export const startWizard = (
message(`Welcome to vscode-jest setup wizard!`);
message(`\t(More info about the setup wizard: ${WIZARD_HELP_URL})`);

const workspace = ws || (await selectWorkspace());
const ws = workspace || (await selectWorkspace());

if (workspace) {
message(`=> workspace "${workspace.name}" is selected`);
if (ws) {
message(`=> workspace "${ws.name}" is selected`);

const context: WizardContext = {
debugConfigProvider,
workspace,
workspace: ws,
message,
verbose,
};

try {
Expand Down
12 changes: 8 additions & 4 deletions src/setup-wizard/tasks/setup-jest-cmdline.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as path from 'path';

import {
showInputBox,
showActionInputBox,
showActionMessage,
getConfirmation,
showActionMenu,
Expand Down Expand Up @@ -65,16 +65,19 @@ export const setupJestCmdLine: SetupTask = async (
};

const edit = async (cmdLine?: string): Promise<WizardStatus> => {
let editedValue = await showInputBox({
let editedValue = await showActionInputBox({
title: 'Enter Jest Command Line',
value: cmdLine,
prompt: 'Note: the command line should match how you run jest tests in terminal ',
enableBackButton: true,
verbose: context.verbose,
});
editedValue = editedValue?.trim();
if (!editedValue) {
message(
`jest command line did not change: jest.jestCommandLine = "${settings.jestCommandLine}"`
`jest command line did not change: jest.jestCommandLine = ${
settings.jestCommandLine ? `"${settings.jestCommandLine}"` : settings.jestCommandLine
}`
);
return 'abort';
}
Expand Down Expand Up @@ -149,6 +152,7 @@ export const setupJestCmdLine: SetupTask = async (
title: 'Set up Jest Command Line',
placeholder,
enableBackButton: true,
verbose: context.verbose,
});
};
const withoutExistingSettings = async (): Promise<WizardStatus> => {
Expand All @@ -174,7 +178,7 @@ export const setupJestCmdLine: SetupTask = async (
return edit();
};

message(`Setup jest command line for workspace "${workspace.name}"`);
message(`Setup jest command line for workspace "${workspace.name}"`, 'setupJestCmdLine');
return settings.jestCommandLine || settings.pathToJest
? withExistingSettings()
: withoutExistingSettings();
Expand Down
4 changes: 3 additions & 1 deletion src/setup-wizard/tasks/setup-jest-debug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ export const setupJestDebug: SetupTask = async (context: WizardContext): Promise
title: 'Set up Debug Config',
enableBackButton: true,
placeholder: 'No existing jest debug config found',
verbose: context.verbose,
});
};
const withExistingConfig = async (): Promise<WizardStatus> => {
Expand Down Expand Up @@ -183,10 +184,11 @@ export const setupJestDebug: SetupTask = async (context: WizardContext): Promise
title: 'Set up Debug Config',
enableBackButton: true,
placeholder: `Found existing debug config: "${DEBUG_CONFIG_NAME}"`,
verbose: context.verbose,
});
};

message(`Set up jest debug config for workspace "${workspace.name}"`);
message(`Set up jest debug config for workspace "${workspace.name}"`, 'setupJestDebug');

const jestDebug = launchConfigs?.find((c) => c.name === DEBUG_CONFIG_NAME);

Expand Down
22 changes: 20 additions & 2 deletions src/setup-wizard/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export interface WizardContext {
workspace: vscode.WorkspaceFolder;

message: (msg: string, section?: string) => void;
verbose?: boolean;
}

export type WizardStatus = 'success' | 'error' | 'abort' | 'exit' | undefined;
Expand All @@ -17,18 +18,35 @@ export type ActionableMenuItem<T = WizardStatus> = vscode.QuickPickItem & Action
export type ActionableButton<T = WizardStatus> = vscode.QuickInputButton & ActionableComp<T>;
export type ActionableMessageItem<T> = vscode.MessageItem & ActionableComp<T>;

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const isActionableButton = (arg: any): arg is ActionableButton<unknown> =>
arg && arg.iconPath && typeof arg.action === 'function';

export type ActionMessageType = 'info' | 'warning' | 'error';

export type AllowBackButton = { enableBackButton?: boolean };
export interface ActionMenuOptions<T = WizardStatus> extends AllowBackButton {
export type Verbose = { verbose?: boolean };

// actionable menu
export type ActionMenuInput<T> = ActionableMenuItem<T> | ActionableButton<T> | undefined;
export type ActionableMenuResult<T = WizardStatus> = T | undefined;
export interface ActionMenuOptions<T = WizardStatus> extends AllowBackButton, Verbose {
title?: string;
placeholder?: string;
value?: string;
rightButtons?: ActionableButton<T>[];
selectItemIdx?: number;
}

export type ActionableResult<T = WizardStatus> = T | undefined;
// actionable input box
export type ActionInputResult<T> = T | string | undefined;
export type ActionInput<T> = ActionInputResult<T> | ActionableButton<T> | undefined;
export interface ActionInputBoxOptions<T> extends AllowBackButton, Verbose {
title?: string;
prompt?: string;
value?: string;
rightButtons?: ActionableButton<T>[];
}

export type SetupTask = (context: WizardContext) => Promise<WizardStatus>;

Expand Down
Loading

0 comments on commit 999b457

Please sign in to comment.