Skip to content
Merged
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
31 changes: 17 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -400,35 +400,35 @@ This setting can be one of the predefined types or a custom object.
2. "terminal": Clear the terminal panel only.
3. "test-results": clear the test results panel only.
4. "none": Do not clear any panel. (default)
(_**Note**: As of the current version, the testing framework does not support the clearing of the "TEST RESULTS" panel without side effects. The closest available command also clears all test item statuses, which may not be desirable. We are aware of this limitation and will raise the issue with the VS Code team._)
(_**Note**: As of the current version, the testing framework does not support the clearing of the "TEST RESULTS" panel without side effects. The closest available command also clears all test item statuses, which may not be desirable. We are aware of this limitation and will raise the issue with the vscode team._)


<a id="outputconfig-conflict"></a>
**Handling Conflicts with "TEST RESULTS" panel setting**

_The Problem_

The behavior of the "TEST RESULTS" panel is influenced by VSCode's native `"testing.openTesting"` setting. This can cause inconsistencies with your `"jest.outputConfig"` settings.
The behavior of the "TEST RESULTS" panel is influenced by VSCode's native `"testing.automaticallyOpenTestResults"` setting. This can cause inconsistencies with your `"jest.outputConfig"` settings.

For instance, if you set `"jest.outputConfig": {"revealWithFocus": "none"}` to prevent automatic focus changes, but leave `"testing.openTesting"` at its default value of `"openOnTestStart"`, the "TEST RESULTS" panel will still automatically switch focus when the tests are run via UI.
For instance, if you set `"jest.outputConfig": {"revealWithFocus": "none"}` to prevent automatic focus changes, but leave `"testing.automaticallyOpenTestResults"` at its default value of `"openOnTestStart"`, the "TEST RESULTS" panel will still automatically switch focus when the tests are run via UI.

_The Universal Solution_

For a consistent Jest output experience, the simplest solution is to set `"testing.openTesting": "neverOpen"`. This allows the extension to manage the "TEST RESULTS" and "TERMINAL" panels together using `"jest.outputConfig"` alone.
For a consistent Jest output experience, the simplest solution is to set `"testing.automaticallyOpenTestResults": "neverOpen"`. This allows the extension to manage the "TEST RESULTS" and "TERMINAL" panels together using `"jest.outputConfig"` alone.

_Further Customization_

However, if you prefer "TEST RESULTS" and "TERMINAL" panels to behave differently and don't mind managing 2 settings yourself, you could play with different combinations.

For instance, if `"testing.openTesting"` is set to `"openOnTestFailure"`, and you want your terminal panel to still reveal when any tests run, your setting would look like this: `"jest.outputConfig": {revealWithFocus: "terminal"}`.
For instance, if `"testing.automaticallyOpenTestResults"` is set to `"openOnTestFailure"`, and you want your terminal panel to still reveal when any tests run, your setting would look like this: `"jest.outputConfig": {revealWithFocus: "terminal"}`.

_Validation and Diagnosis_

The extension features output config diagnosis information in the jest terminal, as well as the built-in conflict detection and quick fixes to assist with the transition.

<a id="default-output-focus"></a>
**Default Output Focus Behavior by RunMode**
When none of the output settings (`"testing.openTesting"` and `"jest.outputConfig"`) are present, The default output behavior is determined by [runMode](#runmode):
When none of the output settings (`"testing.automaticallyOpenTestResults"` and `"jest.outputConfig"`) are present, The default output behavior is determined by [runMode](#runmode):

| runMode| auto reveal "TEST RESULTS" | auto reveal "TERMINAL" |
|:--:|:--:|:--:|
Expand All @@ -440,25 +440,25 @@ When none of the output settings (`"testing.openTesting"` and `"jest.outputConfi
**Configuration Examples**
- Choose a passive output experience that is identical to the previous version: no automatic focus switch, no automatic clear.
```json
"testing.openTesting": "neverOpen",
"testing.automaticallyOpenTestResults": "neverOpen",
"jest.outputConfig": "neutral"
```
- Choose a terminal-based experience and switch focus to it when test run starts.
```json
"testing.openTesting": "neverOpen",
"testing.automaticallyOpenTestResults": "neverOpen",
"jest.outputConfig": "terminal-based"
```
- Choose a test-results-based experience and switch focus to it only when test fails.
```json
"testing.openTesting": "neverOpen",
"testing.automaticallyOpenTestResults": "neverOpen",
"jest.outputConfig": {
"revealOn": "error",
"revealWithFocus": "test-results",
}
```
- Clear the terminal output on each run but do not automatically switch focus to any panel.
```json
"testing.openTesting": "neverOpen",
"testing.automaticallyOpenTestResults": "neverOpen",
"jest.outputConfig": {
"clearOnRun": "terminal"
}
Expand All @@ -472,21 +472,24 @@ When none of the output settings (`"testing.openTesting"` and `"jest.outputConfi
>
> 1. **Workspace Level vs Workspace-Folder Level**: The new `"jest.outputConfig"` is a workspace-level setting, unlike legacy settings like `"jest.autoClearTerminal"` and `"jest.autoRevealOutput"`, which are workspace-folder level settings.
>
> 2. **Backward Compatibility**: If no `"jest.outputConfig"` is defined in your settings.json, the extension will attempt to generate a backward-compatible outputConfig in memory. This uses the `"testing.openTesting"` setting and any legacy settings (`"jest.autoClearTerminal"`, `"jest.autoRevealOutput"`) you might have. Note that this might only work for single-root workspaces.
> 2. **Backward Compatibility**: If no `"jest.outputConfig"` is defined in your settings.json, the extension will attempt to generate a backward-compatible outputConfig in memory. This uses the `"testing.automaticallyOpenTestResults"` setting and any legacy settings (`"jest.autoClearTerminal"`, `"jest.autoRevealOutput"`) you might have. Note that this might only work for single-root workspaces.
>
> 3. **Customization Steps**:
In general it should work out of the box, but if you encounter any issues, here are some steps to help adjusting the output behavior:
> - Use the `"Jest: Save Current Output Config"` command from the command palette to update your settings.json. Then adjust it to fit your needs.
> - Fix warning if any: The save does not include `"testing.openTesting"`, so you might see the conflict warning message. You can either use the "Quick Fix" action or adjust the `settings.json` manually (see [handling conflict](#outputconfig-conflict)).
> - Fix warning if any: The save does not include `"testing.automaticallyOpenTestResults"`, so you might see the conflict warning message. You can either use the "Quick Fix" action or adjust the `settings.json` manually (see [handling conflict](#outputconfig-conflict)).
> - Finally, remove any deprecated settings.
>
> By following these guidelines, you should be able to smoothly transition to using `"jest.outputConfig"`.
> 4. **`testing.openTesting` Migration**:
> **Note:** As of December 2024, the `testing.openTesting` setting has been renamed to `testing.automaticallyOpenTestResults` in vscode. If you previously used `testing.openTesting` in your settings, vscode should have automatically updated it. If not, please update it manually to ensure the extension functions as expected.
>
> Following these steps will help you transition smoothly to using `"jest.outputConfig"`.

---

#### runMode

The `runMode` controls test UX, determining when tests should run, and housing the common run-time toggles like coverage.
The `runMode` controls test UX, determining when tests should run, and housing the common run-time toggles like coverage.

**Type Definitions**
```ts
Expand Down
2 changes: 1 addition & 1 deletion src/JestExt/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ export class JestExt {
'Critical Settings:\r\n' +
`jest.runMode: ${JSON.stringify(pluginSettings.runMode.config, undefined, 4)}\r\n` +
`jest.outputConfig: ${JSON.stringify(outputConfig.value, undefined, 4)}\r\n` +
`testing.openTesting: ${JSON.stringify(openTesting.value, undefined, 4)}\r\n`,
`testing.automaticallyOpenTestResults: ${JSON.stringify(openTesting.value, undefined, 4)}\r\n`,
'info'
);
return pluginSettings;
Expand Down
27 changes: 19 additions & 8 deletions src/output-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,17 @@ export class OutputManager {
}

private initConfigs(): void {
this.openTesting = getSettingDetail('testing', 'openTesting');
// Note: test.openTesting has been replaced with testing.automaticallyOpenTestResults on Nov 2024
const automaticallyOpenTestResults = getSettingDetail<string>(
'testing',
'automaticallyOpenTestResults'
);
if (automaticallyOpenTestResults.isExplicitlySet) {
this.openTesting = automaticallyOpenTestResults;
} else {
const openTesting = getSettingDetail<string>('testing', 'openTesting');
this.openTesting = openTesting.isExplicitlySet ? openTesting : automaticallyOpenTestResults;
}
const config = getSettingDetail<OutputConfig>('jest', 'outputConfig');
const value: OutputConfig = config.value
? this.resolveSetting(config.value)
Expand Down Expand Up @@ -92,7 +102,7 @@ export class OutputManager {
break;
default:
console.warn(
`Unrecognized "testing.openTesting" setting: ${JSON.stringify(this.openTesting)}`
`Unrecognized "testing.automaticallyOpenTestResults" setting: ${JSON.stringify(this.openTesting)}`
);
}

Expand All @@ -101,7 +111,7 @@ export class OutputManager {
config.revealWithFocus = 'none';
if (this.openTesting.value !== 'neverOpen') {
console.warn(
'The "autoRevealOutput" setting is set to "off", but "testing.openTesting" is not set to "neverOpen".'
'The "autoRevealOutput" setting is set to "off", but "testing.automaticallyOpenTestResults" is not set to "neverOpen".'
);
}
}
Expand Down Expand Up @@ -191,9 +201,9 @@ export class OutputManager {
const value = 'neverOpen';
await vscode.workspace
.getConfiguration('testing')
.update('openTesting', value, vscode.ConfigurationTarget.Workspace);
.update('automaticallyOpenTestResults', value, vscode.ConfigurationTarget.Workspace);

console.warn(`set "testing.openTesting" to "${value}"`);
console.warn(`set "testing.automaticallyOpenTestResults" to "${value}"`);
}

public register(): vscode.Disposable[] {
Expand Down Expand Up @@ -249,13 +259,13 @@ export class OutputManager {
return;
}

//check for conflicts between testing.openTesting and jest.outputConfig.revealWithFocus
//check for conflicts between testing.automaticallyOpenTestResults and jest.outputConfig.revealWithFocus
if (this.isTestResultsConfigsValid()) {
return true;
}

const detail =
`Output Config Conflict Detected: test-results panel setting "testing.openTesting: ${this.openTesting.value}" ` +
`Output Config Conflict Detected: test-results panel setting "testing.automaticallyOpenTestResults: ${this.openTesting.value}" ` +
`conflicts with jest.outputConfig:\r\n ${JSON.stringify(this.config.value, undefined, 4)}.`;
console.warn(detail);

Expand Down Expand Up @@ -285,7 +295,7 @@ export class OutputManager {
fixTestResults: {
label: '$(sync) Fix test-results panel setting',
description: '(Extension manages the test-results panel)',
detail: 'Set "testing.openTesting" to "neverOpen"',
detail: 'Set "testing.automaticallyOpenTestResults" to "neverOpen"',
},
fixOutputConfig: {
label: '$(sync-ignored) Fix outputConfig setting',
Expand Down Expand Up @@ -330,6 +340,7 @@ export class OutputManager {
private async onDidChangeConfiguration(e: vscode.ConfigurationChangeEvent): Promise<void> {
if (
e.affectsConfiguration('jest.outputConfig') ||
e.affectsConfiguration('testing.automaticallyOpenTestResults') ||
e.affectsConfiguration('testing.openTesting')
) {
this.initConfigs();
Expand Down
45 changes: 40 additions & 5 deletions tests/output-manager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,33 @@ const mockWorkspace = {

import { getSettingDetail } from '../src/Settings';

interface TestingSettings {
openTesting?: [string | undefined, boolean?];
automaticallyOpenTestResults?: [string | undefined, boolean?];
}
const mockSettings = (outputConfig?: any, openTesting?: string) => {
return mockTestingSettings(outputConfig, {
openTesting: [openTesting],
});
};
const mockTestingSettings = (outputConfig?: any, testingSettings?: TestingSettings) => {
const isExplicitlySet = (values?: [string | undefined, boolean?]): boolean => {
return values?.[1] !== undefined ? !!values?.[1] : values?.[0] !== undefined;
};
(getSettingDetail as jest.Mocked<any>).mockImplementation((_name: string, key: string) => {
console.log('getSettingDetail key', key);
if (key === 'outputConfig') {
return { value: outputConfig, isExplicitlySet: outputConfig !== undefined };
}
if (key === 'openTesting') {
return {
value: openTesting ?? 'openOnTestStart',
isExplicitlySet: openTesting !== undefined,
value: testingSettings?.openTesting?.[0],
isExplicitlySet: isExplicitlySet(testingSettings?.openTesting),
};
}
if (key === 'automaticallyOpenTestResults') {
return {
value: testingSettings?.automaticallyOpenTestResults?.[0] ?? 'openOnTestStart',
isExplicitlySet: isExplicitlySet(testingSettings?.automaticallyOpenTestResults),
};
}
return undefined;
Expand Down Expand Up @@ -108,6 +125,24 @@ describe('OutputManager', () => {
});
});
});
describe('migrate testing.openTesting to testing.automaticallyOpenTestResults', () => {
it.each`
case | openTesting | automaticallyOpenTestResults | expected
${1} | ${[undefined]} | ${[undefined]} | ${['openOnTestStart', false]}
${2} | ${[undefined]} | ${['openOnTestStart', false]} | ${['openOnTestStart', false]}
${3} | ${['neverOpen', true]} | ${['openOnTestStart', false]} | ${['neverOpen', true]}
${4} | ${['neverOpen', true]} | ${['openOnTestStart', true]} | ${['openOnTestStart', true]}
${5} | ${['neverOpen', true]} | ${['openOnTestFailure', true]} | ${['openOnTestFailure', true]}
${6} | ${['neverOpen', true]} | ${[undefined]} | ${['neverOpen', true]}
`('case $case', ({ openTesting, automaticallyOpenTestResults, expected }) => {
mockTestingSettings(undefined, { openTesting, automaticallyOpenTestResults });

const om = new OutputManager();
const { openTesting: config } = om.outputConfigs();
expect(config.value).toEqual(expected[0]);
expect(config.isExplicitlySet).toEqual(expected[1]);
});
});
});

describe('showOutputOn', () => {
Expand Down Expand Up @@ -337,7 +372,7 @@ describe('OutputManager', () => {
const om = new OutputManager();
await om.disableAutoFocus();
expect(mockConfig.update).toHaveBeenCalledWith(
'openTesting',
'automaticallyOpenTestResults',
'neverOpen',
vscode.ConfigurationTarget.Workspace
);
Expand Down Expand Up @@ -561,7 +596,7 @@ describe('OutputManager', () => {
expect(showWarningMessageSpy).toHaveBeenCalled();
expect(showQuickPickSpy).toHaveBeenCalled();
expect(mockConfig.update).toHaveBeenCalledWith(
'openTesting',
'automaticallyOpenTestResults',
'neverOpen',
vscode.ConfigurationTarget.Workspace
);
Expand Down