start with unit tests for interactive editor controller (#183112)

This commit is contained in:
Johannes Rieken 2023-05-22 15:24:20 +02:00 committed by GitHub
parent 487a08afe5
commit 747b57b9f1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 141 additions and 8 deletions

View file

@ -331,6 +331,7 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider {
this._overlayWidget = null;
}
this._arrow?.hide();
this._positionMarkerId.clear();
}
private _decoratingElementsHeight(): number {

View file

@ -21,8 +21,8 @@ export class TestInstantiationService extends InstantiationService {
private _servciesMap: Map<ServiceIdentifier<any>, any>;
constructor(private _serviceCollection: ServiceCollection = new ServiceCollection(), strict: boolean = false) {
super(_serviceCollection, strict);
constructor(private _serviceCollection: ServiceCollection = new ServiceCollection(), strict: boolean = false, parent?: TestInstantiationService) {
super(_serviceCollection, strict, parent);
this._servciesMap = new Map<ServiceIdentifier<any>, any>();
}
@ -125,6 +125,10 @@ export class TestInstantiationService extends InstantiationService {
private isServiceMock(arg1: any): boolean {
return typeof arg1 === 'object' && arg1.hasOwnProperty('id');
}
override createChild(services: ServiceCollection): TestInstantiationService {
return new TestInstantiationService(services, false, this);
}
}
interface SinonOptions {

View file

@ -39,7 +39,7 @@ import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/se
import { CellUri } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
const enum State {
export const enum State {
CREATE_SESSION = 'CREATE_SESSION',
INIT_UI = 'INIT_UI',
WAIT_FOR_INPUT = 'WAIT_FOR_INPUT',
@ -177,11 +177,11 @@ export class InteractiveEditorController implements IEditorContribution {
// ---- state machine
private async _nextState(state: State, options: InteractiveEditorRunOptions | undefined): Promise<void> {
protected async _nextState(state: State, options: InteractiveEditorRunOptions | undefined): Promise<void> {
this._logService.trace('[IE] setState to ', state);
const nextState = await this[state](options);
if (nextState) {
this._nextState(nextState, options);
await this._nextState(nextState, options);
}
}
@ -220,12 +220,13 @@ export class InteractiveEditorController implements IEditorContribution {
case EditMode.Live:
this._strategy = this._instaService.createInstance(LiveStrategy, session, this._editor, this._zone.widget);
break;
case EditMode.LivePreview:
this._strategy = this._instaService.createInstance(LivePreviewStrategy, session, this._editor, this._zone.widget);
break;
case EditMode.Preview:
this._strategy = this._instaService.createInstance(PreviewStrategy, session, this._zone.widget);
break;
case EditMode.LivePreview:
default:
this._strategy = this._instaService.createInstance(LivePreviewStrategy, session, this._editor, this._zone.widget);
break;
}
this._activeSession = session;

View file

@ -0,0 +1,127 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { Range } from 'vs/editor/common/core/range';
import { instantiateTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { InteractiveEditorController, InteractiveEditorRunOptions, State } from 'vs/workbench/contrib/interactiveEditor/browser/interactiveEditorController';
import { IInteractiveEditorSessionService, InteractiveEditorSessionService } from 'vs/workbench/contrib/interactiveEditor/browser/interactiveEditorSession';
import { IInteractiveEditorService, InteractiveEditorResponseType } from 'vs/workbench/contrib/interactiveEditor/common/interactiveEditor';
import { InteractiveEditorServiceImpl } from 'vs/workbench/contrib/interactiveEditor/common/interactiveEditorServiceImpl';
import { workbenchInstantiationService } from 'vs/workbench/test/browser/workbenchTestServices';
import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { IModelService } from 'vs/editor/common/services/model';
import { ITextModel } from 'vs/editor/common/model';
import { IEditorProgressService, IProgressRunner } from 'vs/platform/progress/common/progress';
import { mock } from 'vs/base/test/common/mock';
import { Emitter, Event } from 'vs/base/common/event';
suite('InteractiveEditorController', function () {
class TestController extends InteractiveEditorController {
private readonly _onDidChangeState = new Emitter<State>();
readonly onDidChangeState: Event<State> = this._onDidChangeState.event;
readonly states: readonly State[] = [];
protected override _nextState(state: State, options: InteractiveEditorRunOptions | undefined): Promise<void> {
this._onDidChangeState.fire(state);
(<State[]>this.states).push(state);
return super._nextState(state, options);
}
override dispose() {
super.dispose();
this._onDidChangeState.dispose();
}
}
const store = new DisposableStore();
let editor: ICodeEditor;
let model: ITextModel;
let ctrl: TestController;
// let contextKeys: MockContextKeyService;
let interactiveEditorService: InteractiveEditorServiceImpl;
let instaService: TestInstantiationService;
setup(function () {
const contextKeyService = new MockContextKeyService();
interactiveEditorService = new InteractiveEditorServiceImpl(contextKeyService);
const serviceCollection = new ServiceCollection(
[IContextKeyService, contextKeyService],
[IInteractiveEditorService, interactiveEditorService],
[IInteractiveEditorSessionService, new SyncDescriptor(InteractiveEditorSessionService)],
[IEditorProgressService, new class extends mock<IEditorProgressService>() {
override show(total: unknown, delay?: unknown): IProgressRunner {
return {
total() { },
worked(value) { },
done() { },
};
}
}]
);
instaService = workbenchInstantiationService(undefined, store).createChild(serviceCollection);
model = instaService.get(IModelService).createModel('Hello\nWorld\nHello Again\nHello World\n', null);
editor = instantiateTestCodeEditor(instaService, model);
store.add(interactiveEditorService.addProvider({
debugName: 'Unit Test',
prepareInteractiveEditorSession() {
return {
id: Math.random()
};
},
provideResponse(session, request) {
return {
type: InteractiveEditorResponseType.EditorEdit,
id: Math.random(),
edits: [{
range: new Range(1, 1, 1, 1),
text: request.prompt
}]
};
}
}));
});
teardown(function () {
editor.dispose();
model.dispose();
store.clear();
ctrl?.dispose();
});
test('creation, not showing anything', function () {
ctrl = instaService.createInstance(TestController, editor);
assert.ok(ctrl);
assert.strictEqual(ctrl.getWidgetPosition(), undefined);
});
test('run (show/hide)', async function () {
ctrl = instaService.createInstance(TestController, editor);
const run = ctrl.run({ message: 'Hello', autoSend: true });
await Event.toPromise(Event.filter(ctrl.onDidChangeState, e => e === State.SHOW_RESPONSE));
assert.ok(ctrl.getWidgetPosition() !== undefined);
await ctrl.cancelSession();
await run;
assert.ok(ctrl.getWidgetPosition() === undefined);
});
});