Skip to content

Commit 747b57b

Browse files
authored
start with unit tests for interactive editor controller (microsoft#183112)
1 parent 487a08a commit 747b57b

File tree

4 files changed

+141
-8
lines changed

4 files changed

+141
-8
lines changed

src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,7 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider {
331331
this._overlayWidget = null;
332332
}
333333
this._arrow?.hide();
334+
this._positionMarkerId.clear();
334335
}
335336

336337
private _decoratingElementsHeight(): number {

src/vs/platform/instantiation/test/common/instantiationServiceMock.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ export class TestInstantiationService extends InstantiationService {
2121

2222
private _servciesMap: Map<ServiceIdentifier<any>, any>;
2323

24-
constructor(private _serviceCollection: ServiceCollection = new ServiceCollection(), strict: boolean = false) {
25-
super(_serviceCollection, strict);
24+
constructor(private _serviceCollection: ServiceCollection = new ServiceCollection(), strict: boolean = false, parent?: TestInstantiationService) {
25+
super(_serviceCollection, strict, parent);
2626

2727
this._servciesMap = new Map<ServiceIdentifier<any>, any>();
2828
}
@@ -125,6 +125,10 @@ export class TestInstantiationService extends InstantiationService {
125125
private isServiceMock(arg1: any): boolean {
126126
return typeof arg1 === 'object' && arg1.hasOwnProperty('id');
127127
}
128+
129+
override createChild(services: ServiceCollection): TestInstantiationService {
130+
return new TestInstantiationService(services, false, this);
131+
}
128132
}
129133

130134
interface SinonOptions {

src/vs/workbench/contrib/interactiveEditor/browser/interactiveEditorController.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/se
3939
import { CellUri } from 'vs/workbench/contrib/notebook/common/notebookCommon';
4040
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
4141

42-
const enum State {
42+
export const enum State {
4343
CREATE_SESSION = 'CREATE_SESSION',
4444
INIT_UI = 'INIT_UI',
4545
WAIT_FOR_INPUT = 'WAIT_FOR_INPUT',
@@ -177,11 +177,11 @@ export class InteractiveEditorController implements IEditorContribution {
177177

178178
// ---- state machine
179179

180-
private async _nextState(state: State, options: InteractiveEditorRunOptions | undefined): Promise<void> {
180+
protected async _nextState(state: State, options: InteractiveEditorRunOptions | undefined): Promise<void> {
181181
this._logService.trace('[IE] setState to ', state);
182182
const nextState = await this[state](options);
183183
if (nextState) {
184-
this._nextState(nextState, options);
184+
await this._nextState(nextState, options);
185185
}
186186
}
187187

@@ -220,12 +220,13 @@ export class InteractiveEditorController implements IEditorContribution {
220220
case EditMode.Live:
221221
this._strategy = this._instaService.createInstance(LiveStrategy, session, this._editor, this._zone.widget);
222222
break;
223-
case EditMode.LivePreview:
224-
this._strategy = this._instaService.createInstance(LivePreviewStrategy, session, this._editor, this._zone.widget);
225-
break;
226223
case EditMode.Preview:
227224
this._strategy = this._instaService.createInstance(PreviewStrategy, session, this._zone.widget);
228225
break;
226+
case EditMode.LivePreview:
227+
default:
228+
this._strategy = this._instaService.createInstance(LivePreviewStrategy, session, this._editor, this._zone.widget);
229+
break;
229230
}
230231

231232
this._activeSession = session;
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
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 assert from 'assert';
7+
import { DisposableStore } from 'vs/base/common/lifecycle';
8+
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
9+
import { Range } from 'vs/editor/common/core/range';
10+
import { instantiateTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor';
11+
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
12+
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
13+
import { InteractiveEditorController, InteractiveEditorRunOptions, State } from 'vs/workbench/contrib/interactiveEditor/browser/interactiveEditorController';
14+
import { IInteractiveEditorSessionService, InteractiveEditorSessionService } from 'vs/workbench/contrib/interactiveEditor/browser/interactiveEditorSession';
15+
import { IInteractiveEditorService, InteractiveEditorResponseType } from 'vs/workbench/contrib/interactiveEditor/common/interactiveEditor';
16+
import { InteractiveEditorServiceImpl } from 'vs/workbench/contrib/interactiveEditor/common/interactiveEditorServiceImpl';
17+
import { workbenchInstantiationService } from 'vs/workbench/test/browser/workbenchTestServices';
18+
import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
19+
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
20+
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
21+
import { IModelService } from 'vs/editor/common/services/model';
22+
import { ITextModel } from 'vs/editor/common/model';
23+
import { IEditorProgressService, IProgressRunner } from 'vs/platform/progress/common/progress';
24+
import { mock } from 'vs/base/test/common/mock';
25+
import { Emitter, Event } from 'vs/base/common/event';
26+
27+
suite('InteractiveEditorController', function () {
28+
29+
class TestController extends InteractiveEditorController {
30+
31+
private readonly _onDidChangeState = new Emitter<State>();
32+
readonly onDidChangeState: Event<State> = this._onDidChangeState.event;
33+
34+
readonly states: readonly State[] = [];
35+
36+
protected override _nextState(state: State, options: InteractiveEditorRunOptions | undefined): Promise<void> {
37+
this._onDidChangeState.fire(state);
38+
(<State[]>this.states).push(state);
39+
return super._nextState(state, options);
40+
}
41+
42+
override dispose() {
43+
super.dispose();
44+
this._onDidChangeState.dispose();
45+
}
46+
}
47+
48+
const store = new DisposableStore();
49+
let editor: ICodeEditor;
50+
let model: ITextModel;
51+
let ctrl: TestController;
52+
// let contextKeys: MockContextKeyService;
53+
let interactiveEditorService: InteractiveEditorServiceImpl;
54+
let instaService: TestInstantiationService;
55+
56+
setup(function () {
57+
58+
const contextKeyService = new MockContextKeyService();
59+
interactiveEditorService = new InteractiveEditorServiceImpl(contextKeyService);
60+
61+
const serviceCollection = new ServiceCollection(
62+
[IContextKeyService, contextKeyService],
63+
[IInteractiveEditorService, interactiveEditorService],
64+
[IInteractiveEditorSessionService, new SyncDescriptor(InteractiveEditorSessionService)],
65+
[IEditorProgressService, new class extends mock<IEditorProgressService>() {
66+
override show(total: unknown, delay?: unknown): IProgressRunner {
67+
return {
68+
total() { },
69+
worked(value) { },
70+
done() { },
71+
};
72+
}
73+
}]
74+
);
75+
76+
instaService = workbenchInstantiationService(undefined, store).createChild(serviceCollection);
77+
78+
model = instaService.get(IModelService).createModel('Hello\nWorld\nHello Again\nHello World\n', null);
79+
editor = instantiateTestCodeEditor(instaService, model);
80+
81+
store.add(interactiveEditorService.addProvider({
82+
debugName: 'Unit Test',
83+
prepareInteractiveEditorSession() {
84+
return {
85+
id: Math.random()
86+
};
87+
},
88+
provideResponse(session, request) {
89+
return {
90+
type: InteractiveEditorResponseType.EditorEdit,
91+
id: Math.random(),
92+
edits: [{
93+
range: new Range(1, 1, 1, 1),
94+
text: request.prompt
95+
}]
96+
};
97+
}
98+
}));
99+
});
100+
101+
teardown(function () {
102+
editor.dispose();
103+
model.dispose();
104+
store.clear();
105+
ctrl?.dispose();
106+
});
107+
108+
test('creation, not showing anything', function () {
109+
ctrl = instaService.createInstance(TestController, editor);
110+
assert.ok(ctrl);
111+
assert.strictEqual(ctrl.getWidgetPosition(), undefined);
112+
});
113+
114+
test('run (show/hide)', async function () {
115+
ctrl = instaService.createInstance(TestController, editor);
116+
const run = ctrl.run({ message: 'Hello', autoSend: true });
117+
118+
await Event.toPromise(Event.filter(ctrl.onDidChangeState, e => e === State.SHOW_RESPONSE));
119+
assert.ok(ctrl.getWidgetPosition() !== undefined);
120+
121+
await ctrl.cancelSession();
122+
123+
await run;
124+
125+
assert.ok(ctrl.getWidgetPosition() === undefined);
126+
});
127+
});

0 commit comments

Comments
 (0)