-
Notifications
You must be signed in to change notification settings - Fork 294
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
Enable debugging IW in vscode.web and add tests for IW on web #10297
Changes from 18 commits
b332d00
4f33a75
c353e89
f236045
a8e8c78
f9e3e2e
4a160e6
10ddaa1
3ed6117
c3d969a
a059f54
3900662
1b43926
ab3bde4
3aaf2cf
85ea958
28d6d9c
0bb7275
5b84a21
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 |
---|---|---|
|
@@ -17,13 +17,7 @@ import { | |
import { IDocumentManager, IVSCodeNotebook, IWorkspaceService } from '../../platform/common/application/types'; | ||
import { traceWarning, traceInfoIfCI } from '../../platform/logging'; | ||
|
||
import { | ||
ICellRange, | ||
IConfigurationService, | ||
IDisposableRegistry, | ||
IsWebExtension, | ||
Resource | ||
} from '../../platform/common/types'; | ||
import { ICellRange, IConfigurationService, IDisposableRegistry, Resource } from '../../platform/common/types'; | ||
import * as localize from '../../platform/common/utils/localize'; | ||
import { getInteractiveCellMetadata } from '../helpers'; | ||
import { IKernelProvider } from '../../kernels/types'; | ||
|
@@ -63,8 +57,7 @@ export class CodeLensFactory implements ICodeLensFactory { | |
@inject(IDisposableRegistry) disposables: IDisposableRegistry, | ||
@inject(IGeneratedCodeStorageFactory) | ||
private readonly generatedCodeStorageFactory: IGeneratedCodeStorageFactory, | ||
@inject(IKernelProvider) kernelProvider: IKernelProvider, | ||
@inject(IsWebExtension) private readonly isWebExtension: boolean | ||
@inject(IKernelProvider) kernelProvider: IKernelProvider | ||
) { | ||
this.documentManager.onDidCloseTextDocument(this.onClosedDocument, this, disposables); | ||
this.workspace.onDidGrantWorkspaceTrust(() => this.codeLensCache.clear(), this, disposables); | ||
|
@@ -265,13 +258,9 @@ export class CodeLensFactory implements ICodeLensFactory { | |
Commands.RunCellAndAllBelowPalette | ||
]; | ||
} | ||
if (this.isWebExtension) { | ||
commandsToBeDisabled.push(Commands.DebugCell); | ||
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. Debugging cells in IW web is now enabled. |
||
} | ||
if (commandsToBeDisabled) { | ||
fullCommandList = fullCommandList.filter((item) => !commandsToBeDisabled.includes(item)); | ||
} | ||
|
||
return fullCommandList; | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,8 +22,8 @@ import { traceInfoIfCI } from '../../platform/logging'; | |
import { | ||
CodeLensCommands, | ||
EditorContexts, | ||
PYTHON_FILE, | ||
PYTHON_UNTITLED, | ||
InteractiveInputScheme, | ||
NotebookCellScheme, | ||
Telemetry | ||
} from '../../platform/common/constants'; | ||
import { IDataScienceCodeLensProvider, ICodeWatcher } from './types'; | ||
|
@@ -78,7 +78,7 @@ export class DataScienceCodeLensProvider implements IDataScienceCodeLensProvider | |
// CodeLensProvider interface | ||
// Some implementation based on DonJayamanne's jupyter extension work | ||
public provideCodeLenses(document: vscode.TextDocument, _token: vscode.CancellationToken): vscode.CodeLens[] { | ||
if (document.uri.scheme != PYTHON_FILE.scheme && document.uri.scheme !== PYTHON_UNTITLED.scheme) { | ||
if ([NotebookCellScheme, InteractiveInputScheme].includes(document.uri.scheme)) { | ||
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. Running cells doesn't work in IW on the web unless you open a local folder, i.e. if you open a github repo or any other file system it will not work, hence now enabling it for all except notebook cells & IW input cell. |
||
return []; | ||
} | ||
// Get the list of code lens for this document. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -221,7 +221,7 @@ export class KernelProcess implements IKernelProcess { | |
tcpPortUsed.waitUntilUsed(this.connection.shell_port, 200, timeout), | ||
tcpPortUsed.waitUntilUsed(this.connection.iopub_port, 200, timeout) | ||
]).catch((ex) => { | ||
if (cancelToken.isCancellationRequested) { | ||
if (cancelToken.isCancellationRequested || deferred.rejected) { | ||
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. No need to log errors if the other promise failed |
||
return; | ||
} | ||
traceError(`waitUntilUsed timed out`, ex); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,7 @@ import type { JSONObject } from '@lumino/coreutils'; | |
import { inject, injectable, multiInject, optional } from 'inversify'; | ||
import * as vscode from 'vscode'; | ||
import { ICommandManager, IDocumentManager, IWorkspaceService } from './application/types'; | ||
import { PYTHON_FILE, PYTHON_LANGUAGE, PYTHON_UNTITLED } from './constants'; | ||
import { PYTHON_FILE_ANY_SCHEME, PYTHON_LANGUAGE } from './constants'; | ||
import { ContextKey } from './contextKey'; | ||
import './extensions'; | ||
import { | ||
|
@@ -53,10 +53,7 @@ export class GlobalActivation implements IExtensionSingleActivationService { | |
public async activate(): Promise<void> { | ||
if (this.dataScienceCodeLensProvider) { | ||
this.extensionContext.subscriptions.push( | ||
vscode.languages.registerCodeLensProvider( | ||
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. Running cells doesn't work in IW on the web unless you open a local folder, i.e. if you open a github repo or any other file system it will not work, hence now enabling it for all except notebook cells & IW input cell. |
||
[PYTHON_FILE, PYTHON_UNTITLED], | ||
this.dataScienceCodeLensProvider | ||
) | ||
vscode.languages.registerCodeLensProvider([PYTHON_FILE_ANY_SCHEME], this.dataScienceCodeLensProvider) | ||
); | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,14 +7,25 @@ | |
import * as assert from 'assert'; | ||
import * as fs from 'fs-extra'; | ||
import * as path from '../platform/vscode-path/path'; | ||
import * as tmp from 'tmp'; | ||
import * as uuid from 'uuid/v4'; | ||
import { coerce, SemVer } from 'semver'; | ||
import type { ConfigurationTarget, TextDocument, Uri } from 'vscode'; | ||
import { IProcessService } from '../platform/common/process/types.node'; | ||
import { EXTENSION_ROOT_DIR_FOR_TESTS, IS_MULTI_ROOT_TEST, IS_PERF_TEST, IS_SMOKE_TEST } from './constants.node'; | ||
import { | ||
EXTENSION_ROOT_DIR_FOR_TESTS, | ||
IS_MULTI_ROOT_TEST, | ||
IS_PERF_TEST, | ||
IS_REMOTE_NATIVE_TEST, | ||
IS_SMOKE_TEST | ||
} from './constants.node'; | ||
import { noop } from './core'; | ||
import { isCI } from '../platform/common/constants'; | ||
import { IWorkspaceService } from '../platform/common/application/types'; | ||
import { initializeCommonApi } from './common'; | ||
import { IDisposable } from '../platform/common/types'; | ||
import { swallowExceptions } from '../platform/common/utils/misc'; | ||
import { JupyterServer } from './datascience/jupyterServer.node'; | ||
import type { ConfigurationTarget, NotebookDocument, TextDocument, Uri } from 'vscode'; | ||
|
||
export { createEventHandler } from './common'; | ||
|
||
|
@@ -320,3 +331,42 @@ export async function captureScreenShot(fileNamePrefix: string) { | |
console.error(`Failed to capture screenshot into ${filename}`, ex); | ||
} | ||
} | ||
|
||
export function initializeCommonNodeApi() { | ||
const { commands, Uri } = require('vscode'); | ||
const { initialize } = require('./initialize.node'); | ||
|
||
initializeCommonApi({ | ||
async createTemporaryFile(options: { | ||
contents?: string; | ||
extension: string; | ||
}): Promise<{ file: Uri } & IDisposable> { | ||
const extension = options.extension || '.py'; | ||
const tempFile = tmp.tmpNameSync({ postfix: extension }); | ||
if (options.contents) { | ||
await fs.writeFile(tempFile, options.contents); | ||
} | ||
return { file: Uri.file(tempFile), dispose: () => swallowExceptions(() => fs.unlinkSync(tempFile)) }; | ||
}, | ||
async startJupyterServer(notebook?: NotebookDocument, useCert: boolean = false): Promise<any> { | ||
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. We end up duplicating the test files because some functions like StartJupyter, createTempFile are specific to web vs desktop. |
||
if (IS_REMOTE_NATIVE_TEST()) { | ||
const uriString = useCert | ||
? await JupyterServer.instance.startJupyterWithCert() | ||
: await JupyterServer.instance.startJupyterWithToken(); | ||
console.info(`Jupyter started and listening at ${uriString}`); | ||
return commands.executeCommand('jupyter.selectjupyteruri', false, Uri.parse(uriString), notebook); | ||
} else { | ||
console.info(`Jupyter not started and set to local`); // This is the default | ||
} | ||
}, | ||
async stopJupyterServer() { | ||
if (IS_REMOTE_NATIVE_TEST()) { | ||
return; | ||
} | ||
await JupyterServer.instance.dispose().catch(noop); | ||
}, | ||
async initialize() { | ||
return initialize(); | ||
} | ||
}); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,7 @@ | |
// Licensed under the MIT License. | ||
'use strict'; | ||
|
||
import { Event } from 'vscode'; | ||
import { NotebookDocument, Uri, Event } from 'vscode'; | ||
import { IExtensionApi } from '../platform/api'; | ||
import { IDisposable } from '../platform/common/types'; | ||
import { IServiceContainer, IServiceManager } from '../platform/ioc/types'; | ||
|
@@ -162,3 +162,45 @@ export function createEventHandler<T, K extends keyof T>( | |
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
return new TestEventHandler(obj[eventName] as any, eventName as string, disposables) as any; | ||
} | ||
/** | ||
* API common to web & desktop tests, but with different implementations | ||
*/ | ||
export type CommonApi = { | ||
createTemporaryFile(options: { extension: string; contents?: string }): Promise<{ file: Uri } & IDisposable>; | ||
startJupyterServer(notebook?: NotebookDocument, useCert?: boolean): Promise<void>; | ||
stopJupyterServer?(): Promise<void>; | ||
captureScreenShot?(fileNamePrefix: string): Promise<void>; | ||
initialize(): Promise<IExtensionTestApi>; | ||
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 the functions that are different on each platform, and if we had a common function for them, then we won't have to create two 3 seprate files for the tests, now that we have a common layer for these functions, we have just one single file (tests that run on web & desktop) |
||
}; | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const API: CommonApi = {} as any; | ||
|
||
export function initializeCommonApi(api: CommonApi) { | ||
Object.assign(API, api); | ||
} | ||
|
||
export async function createTemporaryFile(options: { | ||
contents?: string; | ||
extension: string; | ||
}): Promise<{ file: Uri } & IDisposable> { | ||
return API.createTemporaryFile(options); | ||
} | ||
|
||
export async function startJupyterServer(notebook?: NotebookDocument, useCert: boolean = false): Promise<void> { | ||
return API.startJupyterServer(notebook, useCert); | ||
} | ||
|
||
export async function stopJupyterServer() { | ||
if (API.stopJupyterServer) { | ||
return API.stopJupyterServer(); | ||
} | ||
} | ||
export async function captureScreenShot(fileNamePrefix: string) { | ||
if (API.captureScreenShot) { | ||
await API.captureScreenShot(fileNamePrefix); | ||
} | ||
} | ||
|
||
export async function initialize() { | ||
return API.initialize(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
import { commands, NotebookDocument, Uri, workspace } from 'vscode'; | ||
import { IDisposable } from '../platform/common/types'; | ||
import { initializeCommonApi } from './common'; | ||
import { JUPYTER_SERVER_URI } from './constants'; | ||
import * as uuid from 'uuid/v4'; | ||
import { noop } from './core'; | ||
import { initialize } from './initialize'; | ||
|
||
export function initializeCommonWebApi() { | ||
initializeCommonApi({ | ||
async createTemporaryFile(options: { | ||
contents?: string; | ||
extension: string; | ||
}): Promise<{ file: Uri } & IDisposable> { | ||
const folder = workspace.workspaceFolders![0].uri; | ||
const tmpDir = Uri.joinPath(folder, 'temp', 'testFiles'); | ||
try { | ||
await workspace.fs.createDirectory(tmpDir); | ||
} catch { | ||
// ignore if it exists.. | ||
} | ||
const extension = options.extension || '.py'; | ||
const file = Uri.joinPath(tmpDir, `${uuid()}${extension}`); | ||
const contents = options.contents || ''; | ||
|
||
await workspace.fs.writeFile(file, Buffer.from(contents)); | ||
return { | ||
file, | ||
dispose: () => { | ||
workspace.fs.delete(file).then(noop, noop); | ||
} | ||
}; | ||
}, | ||
async startJupyterServer(notebook?: NotebookDocument): Promise<void> { | ||
// Server URI should have been embedded in the constants file | ||
const uri = Uri.parse(JUPYTER_SERVER_URI); | ||
console.log(`ServerURI for remote test: ${JUPYTER_SERVER_URI}`); | ||
// Use this URI to set our jupyter server URI | ||
await commands.executeCommand('jupyter.selectjupyteruri', false, uri, notebook); | ||
}, | ||
async initialize() { | ||
return initialize(); | ||
} | ||
}); | ||
} |
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.
New pattern to run *.vscode.test.ts and *.common.test.ts on desktop.
Unfortunately i cannot use a real glob patter like
(*.vscode.test|*.common.test)
as this breaks the npm script. Using(
and|
in the npm scripts don't work.