-
Notifications
You must be signed in to change notification settings - Fork 676
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
Update option changes toast and switch their tests to jest #6174
Changes from all commits
f80420d
4737540
70b7a37
f4b9617
0532fa9
f7ea716
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
{ | ||
"recommendations": [ | ||
"dbaeumer.vscode-eslint", | ||
"esbenp.prettier-vscode" | ||
"esbenp.prettier-vscode", | ||
"orta.vscode-jest" | ||
] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
/*--------------------------------------------------------------------------------------------- | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License. See License.txt in the project root for license information. | ||
*--------------------------------------------------------------------------------------------*/ | ||
|
||
import * as vscodeAdapter from '../src/vscodeAdapter'; | ||
import { getFakeVsCode } from '../test/unitTests/fakes'; | ||
|
||
// This module creates a manual mock for the vscode module for running in unit tests. | ||
// Jest will automatically pick this up as it is in the __mocks__ directory next to node_modules. | ||
|
||
// We can consider switching to an actual jest mock (instead of this manual fake) once we entirely | ||
// remove the old test framework (mocha/chai). | ||
const vscode: vscodeAdapter.vscode = getFakeVsCode(); | ||
module.exports = vscode; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,8 +39,25 @@ stages: | |
matrix: | ||
linux: | ||
demandsName: ImageOverride -equals Build.Ubuntu.2204.Amd64.Open | ||
windows: | ||
demandsName: ImageOverride -equals 1es-windows-2022-open | ||
pool: | ||
name: NetCore-Public | ||
demands: $(demandsName) | ||
steps: | ||
- template: azure-pipelines/test.yml | ||
|
||
- stage: Test_Omnisharp | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added a separate leg for O# vs blue here - we actually had a few unit tests for blue, but they were running incorrectly under the O# folder. I moved them to the regular tests folder and added a leg to run them in CI as well |
||
displayName: Test Omnisharp | ||
dependsOn: [] | ||
jobs: | ||
- job: Test | ||
strategy: | ||
matrix: | ||
linux: | ||
demandsName: ImageOverride -equals Build.Ubuntu.2204.Amd64.Open | ||
pool: | ||
name: NetCore-Public | ||
demands: $(demandsName) | ||
steps: | ||
- template: azure-pipelines/test-omnisharp.yml |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
steps: | ||
- checkout: self | ||
clean: true | ||
submodules: true | ||
fetchTags: false | ||
fetchDepth: 1 | ||
|
||
- template: prereqs.yml | ||
|
||
- pwsh: | | ||
if ($IsLinux) { | ||
Write-Host "Activating screen emulation" | ||
/usr/bin/Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & | ||
$env:DISPLAY=':99.0' | ||
Write-Host "Now running tests" | ||
} | ||
|
||
npm run omnisharptest | ||
displayName: 🧪 Run unit and integration tests | ||
|
||
- task: PublishPipelineArtifact@1 | ||
condition: failed() | ||
displayName: 'Upload integration test logs' | ||
inputs: | ||
targetPath: '$(Build.SourcesDirectory)/.vscode-test/user-data/logs' | ||
artifactName: 'VSCode Test Logs ($(Agent.JobName)-$(System.JobAttempt))' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/*--------------------------------------------------------------------------------------------- | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License. See License.txt in the project root for license information. | ||
*--------------------------------------------------------------------------------------------*/ | ||
import type { Config } from 'jest'; | ||
|
||
const config: Config = { | ||
verbose: true, | ||
preset: 'ts-jest', | ||
testEnvironment: 'node', | ||
transformIgnorePatterns: ['/dist/.+\\.js'], | ||
// We need to explicity ignore the out directory for modules - otherwise we'll get duplicate vscode module, | ||
// the TS version from the __mocks__ directory and the compiled js version from the out directory. | ||
modulePathIgnorePatterns: ['out'], | ||
// Specify jest to only run tests in jest folders. | ||
// We also have to include the __mocks__ folder. That folder must be next to node_modules so we can't move it, | ||
// but if we specify roots, jest won't automatically pick it up. So we have to specify it here. | ||
roots: ['<rootDir>/test/unitTests', '<rootDir>/omnisharptest/omnisharpJestTests', '<rootDir>/__mocks__'], | ||
}; | ||
|
||
export default config; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
/*--------------------------------------------------------------------------------------------- | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License. See License.txt in the project root for license information. | ||
*--------------------------------------------------------------------------------------------*/ | ||
|
||
import { timeout } from 'rxjs/operators'; | ||
import { from as observableFrom, Subject, BehaviorSubject } from 'rxjs'; | ||
import { Options } from '../../src/shared/options'; | ||
import { registerOmnisharpOptionChanges } from '../../src/omnisharp/omnisharpOptionChanges'; | ||
|
||
import * as jestLib from '@jest/globals'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is possible to globally import jest type definitions so you can just use 'describe' - however the functions will conflict with mocha ones. So for now we manually import the type definitions so we can alias them. We also need to name it something not 'jest' as it will throw errors because jest is already imported (as an alias) by the framework |
||
import * as vscode from 'vscode'; | ||
import { getVSCodeWithConfig, updateConfig } from '../../test/unitTests/fakes'; | ||
|
||
jestLib.describe('OmniSharpConfigChangeObserver', () => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. these are essentially the same tests, just migrated to jest. |
||
let doClickOk: () => void; | ||
let doClickCancel: () => void; | ||
let signalCommandDone: () => void; | ||
let commandDone: Promise<void> | undefined; | ||
let infoMessage: string | undefined; | ||
let invokedCommand: string | undefined; | ||
let optionObservable: Subject<Options>; | ||
|
||
jestLib.beforeEach(() => { | ||
resetMocks(); | ||
optionObservable = new BehaviorSubject<Options>(Options.Read(vscode)); | ||
infoMessage = undefined; | ||
invokedCommand = undefined; | ||
commandDone = new Promise<void>((resolve) => { | ||
signalCommandDone = () => { | ||
resolve(); | ||
}; | ||
}); | ||
registerOmnisharpOptionChanges(optionObservable); | ||
}); | ||
|
||
[ | ||
{ config: 'omnisharp', section: 'path', value: 'somePath' }, | ||
{ config: 'omnisharp', section: 'waitForDebugger', value: true }, | ||
{ config: 'omnisharp', section: 'enableMsBuildLoadProjectsOnDemand', value: true }, | ||
{ config: 'omnisharp', section: 'useModernNet', value: false }, | ||
{ config: 'omnisharp', section: 'loggingLevel', value: 'verbose' }, | ||
].forEach((elem) => { | ||
jestLib.describe(`When the ${elem.config} ${elem.section} changes`, () => { | ||
jestLib.beforeEach(() => { | ||
jestLib.expect(infoMessage).toBe(undefined); | ||
jestLib.expect(invokedCommand).toBe(undefined); | ||
updateConfig(vscode, elem.config, elem.section, elem.value); | ||
optionObservable.next(Options.Read(vscode)); | ||
}); | ||
|
||
jestLib.test(`The information message is shown`, async () => { | ||
jestLib | ||
.expect(infoMessage) | ||
.toEqual( | ||
'C# configuration has changed. Would you like to relaunch the Language Server with your changes?' | ||
); | ||
}); | ||
|
||
jestLib.test( | ||
'Given an information message if the user clicks cancel, the command is not executed', | ||
async () => { | ||
doClickCancel(); | ||
const from = observableFrom(commandDone!).pipe(timeout(1)); | ||
const fromPromise = from.toPromise(); | ||
await jestLib.expect(fromPromise).rejects.toThrow(); | ||
jestLib.expect(invokedCommand).toBe(undefined); | ||
} | ||
); | ||
|
||
jestLib.test( | ||
'Given an information message if the user clicks Reload, the command is executed', | ||
async () => { | ||
doClickOk(); | ||
await commandDone; | ||
jestLib.expect(invokedCommand).toEqual('o.restart'); | ||
} | ||
); | ||
}); | ||
}); | ||
|
||
[{ config: 'dotnet', section: 'server.useOmnisharp', value: true }].forEach((elem) => { | ||
jestLib.describe(`When the ${elem.config} ${elem.section} changes`, () => { | ||
jestLib.beforeEach(() => { | ||
jestLib.expect(infoMessage).toBe(undefined); | ||
jestLib.expect(invokedCommand).toBe(undefined); | ||
updateConfig(vscode, elem.config, elem.section, elem.value); | ||
optionObservable.next(Options.Read(vscode)); | ||
}); | ||
|
||
jestLib.test(`The information message is shown`, async () => { | ||
jestLib | ||
.expect(infoMessage) | ||
.toEqual( | ||
'dotnet.server.useOmnisharp option has changed. Please reload the window to apply the change' | ||
); | ||
}); | ||
|
||
jestLib.test( | ||
'Given an information message if the user clicks cancel, the command is not executed', | ||
async () => { | ||
doClickCancel(); | ||
const from = observableFrom(commandDone!).pipe(timeout(1)); | ||
const fromPromise = from.toPromise(); | ||
await jestLib.expect(fromPromise).rejects.toThrow(); | ||
jestLib.expect(invokedCommand).toBe(undefined); | ||
} | ||
); | ||
|
||
jestLib.test( | ||
'Given an information message if the user clicks Reload, the command is executed', | ||
async () => { | ||
doClickOk(); | ||
await commandDone; | ||
jestLib.expect(invokedCommand).toEqual('workbench.action.reloadWindow'); | ||
} | ||
); | ||
}); | ||
}); | ||
|
||
[ | ||
{ config: 'csharp', section: 'disableCodeActions', value: true }, | ||
{ config: 'csharp', section: 'testsCodeLens.enabled', value: false }, | ||
{ config: 'omnisharp', section: 'referencesCodeLens.enabled', value: false }, | ||
{ config: 'csharp', section: 'format.enable', value: false }, | ||
{ config: 'omnisharp', section: 'useEditorFormattingSettings', value: false }, | ||
{ config: 'omnisharp', section: 'maxProjectResults', value: 1000 }, | ||
{ config: 'omnisharp', section: 'projectLoadTimeout', value: 1000 }, | ||
{ config: 'omnisharp', section: 'autoStart', value: false }, | ||
].forEach((elem) => { | ||
jestLib.test(`Information Message is not shown on change in ${elem.config}.${elem.section}`, () => { | ||
jestLib.expect(infoMessage).toBe(undefined); | ||
jestLib.expect(invokedCommand).toBe(undefined); | ||
updateConfig(vscode, elem.config, elem.section, elem.value); | ||
optionObservable.next(Options.Read(vscode)); | ||
jestLib.expect(infoMessage).toBe(undefined); | ||
}); | ||
}); | ||
|
||
function resetMocks() { | ||
vscode.window.showInformationMessage = async <T>(message: string, ...items: T[]) => { | ||
infoMessage = message; | ||
return new Promise<T | undefined>((resolve) => { | ||
doClickCancel = () => { | ||
resolve(undefined); | ||
}; | ||
|
||
doClickOk = () => { | ||
resolve(items[0]); | ||
}; | ||
}); | ||
}; | ||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
//@ts-ignore | ||
vscode.commands.executeCommand = async (command: string, ..._: any[]) => { | ||
invokedCommand = command; | ||
signalCommandDone(); | ||
return undefined; | ||
}; | ||
|
||
// This has to be replaced before every test to ensure that the config is reset. | ||
getVSCodeWithConfig(vscode); | ||
} | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this adds the jest test explorer - which is how you run and debug tests without manually configuring launch.json