Skip to content

Commit 0d2c3fe

Browse files
authored
Merge pull request #6174 from dibarbet/jesting
Update option changes toast and switch their tests to jest
2 parents fc6c9d3 + f7ea716 commit 0d2c3fe

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+21173
-13631
lines changed

.vscode/extensions.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"recommendations": [
33
"dbaeumer.vscode-eslint",
4-
"esbenp.prettier-vscode"
4+
"esbenp.prettier-vscode",
5+
"orta.vscode-jest"
56
]
67
}

__mocks__/vscode.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import * as vscodeAdapter from '../src/vscodeAdapter';
7+
import { getFakeVsCode } from '../test/unitTests/fakes';
8+
9+
// This module creates a manual mock for the vscode module for running in unit tests.
10+
// Jest will automatically pick this up as it is in the __mocks__ directory next to node_modules.
11+
12+
// We can consider switching to an actual jest mock (instead of this manual fake) once we entirely
13+
// remove the old test framework (mocha/chai).
14+
const vscode: vscodeAdapter.vscode = getFakeVsCode();
15+
module.exports = vscode;

azure-pipelines.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,25 @@ stages:
3939
matrix:
4040
linux:
4141
demandsName: ImageOverride -equals Build.Ubuntu.2204.Amd64.Open
42+
windows:
43+
demandsName: ImageOverride -equals 1es-windows-2022-open
4244
pool:
4345
name: NetCore-Public
4446
demands: $(demandsName)
4547
steps:
4648
- template: azure-pipelines/test.yml
49+
50+
- stage: Test_Omnisharp
51+
displayName: Test Omnisharp
52+
dependsOn: []
53+
jobs:
54+
- job: Test
55+
strategy:
56+
matrix:
57+
linux:
58+
demandsName: ImageOverride -equals Build.Ubuntu.2204.Amd64.Open
59+
pool:
60+
name: NetCore-Public
61+
demands: $(demandsName)
62+
steps:
63+
- template: azure-pipelines/test-omnisharp.yml

azure-pipelines/test-omnisharp.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
steps:
2+
- checkout: self
3+
clean: true
4+
submodules: true
5+
fetchTags: false
6+
fetchDepth: 1
7+
8+
- template: prereqs.yml
9+
10+
- pwsh: |
11+
if ($IsLinux) {
12+
Write-Host "Activating screen emulation"
13+
/usr/bin/Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
14+
$env:DISPLAY=':99.0'
15+
Write-Host "Now running tests"
16+
}
17+
18+
npm run omnisharptest
19+
displayName: 🧪 Run unit and integration tests
20+
21+
- task: PublishPipelineArtifact@1
22+
condition: failed()
23+
displayName: 'Upload integration test logs'
24+
inputs:
25+
targetPath: '$(Build.SourcesDirectory)/.vscode-test/user-data/logs'
26+
artifactName: 'VSCode Test Logs ($(Agent.JobName)-$(System.JobAttempt))'

azure-pipelines/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ steps:
1515
Write-Host "Now running tests"
1616
}
1717
18-
npm run omnisharptest
18+
npm run test
1919
displayName: 🧪 Run unit and integration tests
2020

2121
- task: PublishPipelineArtifact@1

jest.config.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
import type { Config } from 'jest';
6+
7+
const config: Config = {
8+
verbose: true,
9+
preset: 'ts-jest',
10+
testEnvironment: 'node',
11+
transformIgnorePatterns: ['/dist/.+\\.js'],
12+
// We need to explicity ignore the out directory for modules - otherwise we'll get duplicate vscode module,
13+
// the TS version from the __mocks__ directory and the compiled js version from the out directory.
14+
modulePathIgnorePatterns: ['out'],
15+
// Specify jest to only run tests in jest folders.
16+
// We also have to include the __mocks__ folder. That folder must be next to node_modules so we can't move it,
17+
// but if we specify roots, jest won't automatically pick it up. So we have to specify it here.
18+
roots: ['<rootDir>/test/unitTests', '<rootDir>/omnisharptest/omnisharpJestTests', '<rootDir>/__mocks__'],
19+
};
20+
21+
export default config;

l10n/bundle.l10n.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,15 @@
118118
"View Debug Docs": "View Debug Docs",
119119
"Ignore": "Ignore",
120120
"Run and Debug: A valid browser is not installed": "Run and Debug: A valid browser is not installed",
121+
"dotnet.server.useOmnisharp option has changed. Please reload the window to apply the change": "dotnet.server.useOmnisharp option has changed. Please reload the window to apply the change",
122+
"Reload Window": "Reload Window",
123+
"C# configuration has changed. Would you like to relaunch the Language Server with your changes?": "C# configuration has changed. Would you like to relaunch the Language Server with your changes?",
124+
"Restart Language Server": "Restart Language Server",
121125
"Your workspace has multiple Visual Studio Solution files; please select one to get full IntelliSense.": "Your workspace has multiple Visual Studio Solution files; please select one to get full IntelliSense.",
122126
"Choose": "Choose",
123127
"Choose and set default": "Choose and set default",
124128
"Do not load any": "Do not load any",
125-
"Restart Language Server": "Restart Language Server",
129+
"C# configuration has changed. Would you like to reload the window to apply your changes?": "C# configuration has changed. Would you like to reload the window to apply your changes?",
126130
"pipeArgs must be a string or a string array type": "pipeArgs must be a string or a string array type",
127131
"Name not defined in current configuration.": "Name not defined in current configuration.",
128132
"Configuration \"{0}\" in launch.json does not have a {1} argument with {2} for remote process listing.": "Configuration \"{0}\" in launch.json does not have a {1} argument with {2} for remote process listing.",

omnisharptest/omnisharpIntegrationTests/logging/telemetryObserver.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
ProjectConfiguration,
1919
TelemetryErrorEvent,
2020
} from '../../../src/omnisharp/loggingEvents';
21-
import { getNullTelemetryReporter } from '../../omnisharpUnitTests/testAssets/fakes';
21+
import { getNullTelemetryReporter } from '../../../test/unitTests/fakes';
2222
import { Package } from '../../../src/packageManager/package';
2323
import { PackageError } from '../../../src/packageManager/packageError';
2424
import { isNotNull } from '../../testUtil';
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { timeout } from 'rxjs/operators';
7+
import { from as observableFrom, Subject, BehaviorSubject } from 'rxjs';
8+
import { Options } from '../../src/shared/options';
9+
import { registerOmnisharpOptionChanges } from '../../src/omnisharp/omnisharpOptionChanges';
10+
11+
import * as jestLib from '@jest/globals';
12+
import * as vscode from 'vscode';
13+
import { getVSCodeWithConfig, updateConfig } from '../../test/unitTests/fakes';
14+
15+
jestLib.describe('OmniSharpConfigChangeObserver', () => {
16+
let doClickOk: () => void;
17+
let doClickCancel: () => void;
18+
let signalCommandDone: () => void;
19+
let commandDone: Promise<void> | undefined;
20+
let infoMessage: string | undefined;
21+
let invokedCommand: string | undefined;
22+
let optionObservable: Subject<Options>;
23+
24+
jestLib.beforeEach(() => {
25+
resetMocks();
26+
optionObservable = new BehaviorSubject<Options>(Options.Read(vscode));
27+
infoMessage = undefined;
28+
invokedCommand = undefined;
29+
commandDone = new Promise<void>((resolve) => {
30+
signalCommandDone = () => {
31+
resolve();
32+
};
33+
});
34+
registerOmnisharpOptionChanges(optionObservable);
35+
});
36+
37+
[
38+
{ config: 'omnisharp', section: 'path', value: 'somePath' },
39+
{ config: 'omnisharp', section: 'waitForDebugger', value: true },
40+
{ config: 'omnisharp', section: 'enableMsBuildLoadProjectsOnDemand', value: true },
41+
{ config: 'omnisharp', section: 'useModernNet', value: false },
42+
{ config: 'omnisharp', section: 'loggingLevel', value: 'verbose' },
43+
].forEach((elem) => {
44+
jestLib.describe(`When the ${elem.config} ${elem.section} changes`, () => {
45+
jestLib.beforeEach(() => {
46+
jestLib.expect(infoMessage).toBe(undefined);
47+
jestLib.expect(invokedCommand).toBe(undefined);
48+
updateConfig(vscode, elem.config, elem.section, elem.value);
49+
optionObservable.next(Options.Read(vscode));
50+
});
51+
52+
jestLib.test(`The information message is shown`, async () => {
53+
jestLib
54+
.expect(infoMessage)
55+
.toEqual(
56+
'C# configuration has changed. Would you like to relaunch the Language Server with your changes?'
57+
);
58+
});
59+
60+
jestLib.test(
61+
'Given an information message if the user clicks cancel, the command is not executed',
62+
async () => {
63+
doClickCancel();
64+
const from = observableFrom(commandDone!).pipe(timeout(1));
65+
const fromPromise = from.toPromise();
66+
await jestLib.expect(fromPromise).rejects.toThrow();
67+
jestLib.expect(invokedCommand).toBe(undefined);
68+
}
69+
);
70+
71+
jestLib.test(
72+
'Given an information message if the user clicks Reload, the command is executed',
73+
async () => {
74+
doClickOk();
75+
await commandDone;
76+
jestLib.expect(invokedCommand).toEqual('o.restart');
77+
}
78+
);
79+
});
80+
});
81+
82+
[{ config: 'dotnet', section: 'server.useOmnisharp', value: true }].forEach((elem) => {
83+
jestLib.describe(`When the ${elem.config} ${elem.section} changes`, () => {
84+
jestLib.beforeEach(() => {
85+
jestLib.expect(infoMessage).toBe(undefined);
86+
jestLib.expect(invokedCommand).toBe(undefined);
87+
updateConfig(vscode, elem.config, elem.section, elem.value);
88+
optionObservable.next(Options.Read(vscode));
89+
});
90+
91+
jestLib.test(`The information message is shown`, async () => {
92+
jestLib
93+
.expect(infoMessage)
94+
.toEqual(
95+
'dotnet.server.useOmnisharp option has changed. Please reload the window to apply the change'
96+
);
97+
});
98+
99+
jestLib.test(
100+
'Given an information message if the user clicks cancel, the command is not executed',
101+
async () => {
102+
doClickCancel();
103+
const from = observableFrom(commandDone!).pipe(timeout(1));
104+
const fromPromise = from.toPromise();
105+
await jestLib.expect(fromPromise).rejects.toThrow();
106+
jestLib.expect(invokedCommand).toBe(undefined);
107+
}
108+
);
109+
110+
jestLib.test(
111+
'Given an information message if the user clicks Reload, the command is executed',
112+
async () => {
113+
doClickOk();
114+
await commandDone;
115+
jestLib.expect(invokedCommand).toEqual('workbench.action.reloadWindow');
116+
}
117+
);
118+
});
119+
});
120+
121+
[
122+
{ config: 'csharp', section: 'disableCodeActions', value: true },
123+
{ config: 'csharp', section: 'testsCodeLens.enabled', value: false },
124+
{ config: 'omnisharp', section: 'referencesCodeLens.enabled', value: false },
125+
{ config: 'csharp', section: 'format.enable', value: false },
126+
{ config: 'omnisharp', section: 'useEditorFormattingSettings', value: false },
127+
{ config: 'omnisharp', section: 'maxProjectResults', value: 1000 },
128+
{ config: 'omnisharp', section: 'projectLoadTimeout', value: 1000 },
129+
{ config: 'omnisharp', section: 'autoStart', value: false },
130+
].forEach((elem) => {
131+
jestLib.test(`Information Message is not shown on change in ${elem.config}.${elem.section}`, () => {
132+
jestLib.expect(infoMessage).toBe(undefined);
133+
jestLib.expect(invokedCommand).toBe(undefined);
134+
updateConfig(vscode, elem.config, elem.section, elem.value);
135+
optionObservable.next(Options.Read(vscode));
136+
jestLib.expect(infoMessage).toBe(undefined);
137+
});
138+
});
139+
140+
function resetMocks() {
141+
vscode.window.showInformationMessage = async <T>(message: string, ...items: T[]) => {
142+
infoMessage = message;
143+
return new Promise<T | undefined>((resolve) => {
144+
doClickCancel = () => {
145+
resolve(undefined);
146+
};
147+
148+
doClickOk = () => {
149+
resolve(items[0]);
150+
};
151+
});
152+
};
153+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
154+
//@ts-ignore
155+
vscode.commands.executeCommand = async (command: string, ..._: any[]) => {
156+
invokedCommand = command;
157+
signalCommandDone();
158+
return undefined;
159+
};
160+
161+
// This has to be replaced before every test to ensure that the config is reset.
162+
getVSCodeWithConfig(vscode);
163+
}
164+
});

omnisharptest/omnisharpUnitTests/features/reportIssue.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
import { getFakeVsCode } from '../testAssets/fakes';
76
import reportIssue from '../../../src/shared/reportIssue';
87
import { expect } from 'chai';
98
import { vscode } from '../../../src/vscodeAdapter';
@@ -12,6 +11,7 @@ import { FakeMonoResolver, fakeMonoInfo } from '../fakes/fakeMonoResolver';
1211
import { FakeDotnetResolver } from '../fakes/fakeDotnetResolver';
1312
import { DotnetInfo } from '../../../src/shared/utils/dotnetInfo';
1413
import { getEmptyOptions } from '../fakes/fakeOptions';
14+
import { getFakeVsCode } from '../../../test/unitTests/fakes';
1515

1616
suite(`${reportIssue.name}`, () => {
1717
const vscodeVersion = 'myVersion';

0 commit comments

Comments
 (0)