Skip to content

Commit e653396

Browse files
test(e2e): edit flow
1 parent 4b97663 commit e653396

15 files changed

+227
-31
lines changed

.eslintrc.shared.json

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
},
77
"plugins": ["@typescript-eslint", "import"],
88
"rules": {
9+
"@typescript-eslint/naming-convention": "off",
910
"@typescript-eslint/semi": "warn",
1011
"curly": "warn",
1112
"eqeqeq": "warn",

extensions/vscode/.eslintrc.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55
},
66
"extends": ["../../.eslintrc.shared.json"],
77
"rules": {
8-
"@typescript-eslint/naming-convention": "warn"
8+
"@typescript-eslint/naming-convention": "off"
99
}
1010
}

extensions/vscode/e2e/TestUtils.ts

+2-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
import { expect } from "chai";
2-
import {
3-
Key,
4-
WebElement,
5-
waitForAttributeValue,
6-
} from "vscode-extension-tester";
2+
import { Key } from "vscode-extension-tester";
3+
74
import { DEFAULT_TIMEOUT } from "./constants";
85

96
export class TestUtils {

extensions/vscode/e2e/actions/Autocomplete.actions.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { TextEditor } from "vscode-extension-tester";
2-
import { TestUtils } from "../TestUtils";
3-
import { AutocompleteSelectors } from "../selectors/Autocomplete.selectors";
41
import { expect } from "chai";
2+
import { TextEditor } from "vscode-extension-tester";
3+
54
import { DEFAULT_TIMEOUT } from "../constants";
5+
import { AutocompleteSelectors } from "../selectors/Autocomplete.selectors";
6+
import { TestUtils } from "../TestUtils";
67

78
export class AutocompleteActions {
89
public static async testCompletions(editor: TextEditor) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { TextEditor, WebView } from "vscode-extension-tester";
2+
3+
import { EditSelectors } from "../selectors/Edit.selectors";
4+
import { TestUtils } from "../TestUtils";
5+
6+
export class EditActions {
7+
static async invokeEditShortcut(editor: TextEditor) {
8+
editor
9+
.getDriver()
10+
.actions()
11+
.keyDown(TestUtils.osControlKey)
12+
.sendKeys("i")
13+
.keyUp(TestUtils.osControlKey)
14+
.perform();
15+
}
16+
17+
static async acceptEditInGUI(view: WebView): Promise<void> {
18+
await TestUtils.waitForSuccess(async () =>
19+
(await EditSelectors.getEditAcceptButton(view)).click(),
20+
);
21+
await view.switchBack();
22+
}
23+
24+
static async rejectEditInGUI(view: WebView): Promise<void> {
25+
await TestUtils.waitForSuccess(async () =>
26+
(await EditSelectors.getEditRejectButton(view)).click(),
27+
);
28+
await view.switchBack();
29+
}
30+
31+
static async acceptEditWithCodeLens(editor: TextEditor): Promise<void> {
32+
const acceptCodeLens = await editor.getCodeLens("Accept");
33+
await acceptCodeLens?.click();
34+
}
35+
36+
static async rejectEditWithCodeLens(editor: TextEditor): Promise<void> {
37+
const rejectCodeLens = await editor.getCodeLens("Reject");
38+
await rejectCodeLens?.click();
39+
}
40+
}

extensions/vscode/e2e/actions/GUI.actions.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ import {
66
WebView,
77
Workbench,
88
} from "vscode-extension-tester";
9+
10+
import { DEFAULT_TIMEOUT } from "../constants";
911
import { GUISelectors } from "../selectors/GUI.selectors";
1012
import { TestUtils } from "../TestUtils";
11-
import { DEFAULT_TIMEOUT } from "../constants";
1213

1314
export class GUIActions {
1415
public static moveContinueToSidebar = async (driver: WebDriver) => {
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,29 @@
1-
import { VSBrowser, WebView } from "vscode-extension-tester";
1+
import {
2+
EditorView,
3+
InputBox,
4+
TextEditor,
5+
VSBrowser,
6+
Workbench,
7+
} from "vscode-extension-tester";
8+
9+
import { DEFAULT_TIMEOUT } from "../constants";
210

311
export class GlobalActions {
412
public static async openTestWorkspace() {
513
return VSBrowser.instance.openResources("e2e/test-continue");
614
}
15+
16+
public static async createAndOpenNewTextFile(): Promise<{
17+
editor: TextEditor;
18+
}> {
19+
await new Workbench().executeCommand("Create: New File...");
20+
await (
21+
await InputBox.create(DEFAULT_TIMEOUT.MD)
22+
).selectQuickPick("Text File");
23+
const editor = (await new EditorView().openEditor(
24+
"Untitled-1",
25+
)) as TextEditor;
26+
27+
return { editor };
28+
}
729
}

extensions/vscode/e2e/actions/KeyboardShortcuts.actions.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
import { TextEditor, WebDriver, WebView } from "vscode-extension-tester";
2-
3-
import { TestUtils } from "../TestUtils";
1+
import { TextEditor } from "vscode-extension-tester";
42

53
export class KeyboardShortcutsActions {
64
/**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { WebView } from "vscode-extension-tester";
2+
3+
import { SelectorUtils } from "./SelectorUtils";
4+
5+
export class EditSelectors {
6+
public static getEditAcceptButton(view: WebView) {
7+
return SelectorUtils.getElementByDataTestId(view, "edit-accept-button");
8+
}
9+
10+
public static getEditRejectButton(view: WebView) {
11+
return SelectorUtils.getElementByDataTestId(view, "edit-reject-button");
12+
}
13+
}

extensions/vscode/e2e/selectors/GUI.selectors.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { By, until, WebDriver, WebView } from "vscode-extension-tester";
1+
import { By, WebDriver, WebView } from "vscode-extension-tester";
2+
23
import { SelectorUtils } from "./SelectorUtils";
34

45
export class GUISelectors {

extensions/vscode/e2e/tests/Autocomplete.test.ts

+4-13
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,8 @@
1-
import {
2-
EditorView,
3-
TextEditor,
4-
InputBox,
5-
Workbench,
6-
} from "vscode-extension-tester";
1+
import { EditorView, TextEditor } from "vscode-extension-tester";
72

8-
import { DEFAULT_TIMEOUT } from "../constants";
9-
import { GlobalActions } from "../actions/Global.actions";
103
import { AutocompleteActions } from "../actions/Autocomplete.actions";
4+
import { GlobalActions } from "../actions/Global.actions";
5+
import { DEFAULT_TIMEOUT } from "../constants";
116

127
describe("Autocomplete", () => {
138
let editor: TextEditor;
@@ -16,11 +11,7 @@ describe("Autocomplete", () => {
1611
this.timeout(DEFAULT_TIMEOUT.XL);
1712

1813
await GlobalActions.openTestWorkspace();
19-
await new Workbench().executeCommand("Create: New File...");
20-
await (
21-
await InputBox.create(DEFAULT_TIMEOUT.MD)
22-
).selectQuickPick("Text File");
23-
editor = (await new EditorView().openEditor("Untitled-1")) as TextEditor;
14+
({ editor } = await GlobalActions.createAndOpenNewTextFile());
2415
});
2516

2617
afterEach(async function () {
+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import {
2+
EditorView,
3+
WebView,
4+
WebDriver,
5+
Key,
6+
VSBrowser,
7+
InputBox,
8+
TextEditor,
9+
Workbench,
10+
} from "vscode-extension-tester";
11+
12+
import { EditActions } from "../actions/Edit.actions";
13+
import { GlobalActions } from "../actions/Global.actions";
14+
import { GUIActions } from "../actions/GUI.actions";
15+
import { DEFAULT_TIMEOUT } from "../constants";
16+
import { EditSelectors } from "../selectors/Edit.selectors";
17+
import { GUISelectors } from "../selectors/GUI.selectors";
18+
import { TestUtils } from "../TestUtils";
19+
20+
describe("Edit Test", () => {
21+
let view: WebView;
22+
let editor: TextEditor;
23+
let originalEditorText = "Hello world!";
24+
let { userMessage, llmResponse } = TestUtils.generateTestMessagePair();
25+
26+
before(async function () {
27+
this.timeout(DEFAULT_TIMEOUT.XL);
28+
await GUIActions.moveContinueToSidebar(VSBrowser.instance.driver);
29+
await GlobalActions.openTestWorkspace();
30+
({ editor } = await GlobalActions.createAndOpenNewTextFile());
31+
});
32+
33+
beforeEach(async function () {
34+
this.timeout(DEFAULT_TIMEOUT.XL);
35+
36+
await GUIActions.toggleGui();
37+
38+
await editor.typeTextAt(1, 1, originalEditorText);
39+
await editor.selectText(originalEditorText);
40+
41+
await EditActions.invokeEditShortcut(editor);
42+
43+
({ view } = await GUIActions.switchToReactIframe());
44+
45+
await GUIActions.sendMessage({
46+
view,
47+
message: userMessage,
48+
inputFieldIndex: 0,
49+
});
50+
51+
await view.switchBack();
52+
53+
await TestUtils.waitForSuccess(async () => {
54+
const editorText = await editor.getText();
55+
return editorText.includes(llmResponse);
56+
});
57+
});
58+
59+
afterEach(async function () {
60+
this.timeout(DEFAULT_TIMEOUT.XL);
61+
await editor.clearText();
62+
});
63+
64+
it("Accepts an Edit in the GUI", async () => {
65+
({ view } = await GUIActions.switchToReactIframe());
66+
67+
await EditActions.acceptEditInGUI(view);
68+
69+
await view.switchBack();
70+
71+
const editorText = await editor.getText();
72+
73+
await TestUtils.waitForSuccess(
74+
async () =>
75+
!editorText.includes(originalEditorText) &&
76+
editorText.includes(llmResponse),
77+
DEFAULT_TIMEOUT.SM,
78+
);
79+
}).timeout(DEFAULT_TIMEOUT.XL);
80+
81+
it("Rejects an Edit in the GUI", async () => {
82+
({ view } = await GUIActions.switchToReactIframe());
83+
84+
await EditActions.rejectEditInGUI(view);
85+
86+
await view.switchBack();
87+
88+
const editorText = await editor.getText();
89+
90+
await TestUtils.waitForSuccess(
91+
async () =>
92+
editorText.includes(originalEditorText) &&
93+
!editorText.includes(llmResponse),
94+
DEFAULT_TIMEOUT.SM,
95+
);
96+
}).timeout(DEFAULT_TIMEOUT.XL);
97+
98+
it("Accepts an Edit using CodeLens buttons", async () => {
99+
const acceptCodeLens = await editor.getCodeLens("Accept");
100+
await acceptCodeLens?.click();
101+
102+
const editorText = await editor.getText();
103+
104+
await TestUtils.waitForSuccess(
105+
async () =>
106+
!editorText.includes(originalEditorText) &&
107+
editorText.includes(llmResponse),
108+
DEFAULT_TIMEOUT.SM,
109+
);
110+
}).timeout(DEFAULT_TIMEOUT.XL);
111+
112+
it("Rejects an Edit using CodeLens buttons", async () => {
113+
const rejectCodeLens = await editor.getCodeLens("Reject");
114+
await rejectCodeLens?.click();
115+
116+
const editorText = await editor.getText();
117+
118+
await TestUtils.waitForSuccess(
119+
async () =>
120+
!editorText.includes(originalEditorText) &&
121+
editorText.includes(llmResponse),
122+
DEFAULT_TIMEOUT.SM,
123+
);
124+
}).timeout(DEFAULT_TIMEOUT.XL);
125+
});

extensions/vscode/e2e/tests/GUI.test.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { expect } from "chai";
12
import {
23
EditorView,
34
WebView,
@@ -7,12 +8,12 @@ import {
78
VSBrowser,
89
until,
910
} from "vscode-extension-tester";
10-
import { expect } from "chai";
11+
12+
import { GlobalActions } from "../actions/Global.actions";
1113
import { GUIActions } from "../actions/GUI.actions";
14+
import { DEFAULT_TIMEOUT } from "../constants";
1215
import { GUISelectors } from "../selectors/GUI.selectors";
1316
import { TestUtils } from "../TestUtils";
14-
import { DEFAULT_TIMEOUT } from "../constants";
15-
import { GlobalActions } from "../actions/Global.actions";
1617

1718
describe("GUI Test", () => {
1819
let view: WebView;

gui/.eslintrc.json

+3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
// "plugin:@typescript-eslint/recommended-requiring-type-checking"
1212
// "plugin:react/recommended"
1313
],
14+
"rules": {
15+
"@typescript-eslint/naming-convention": "off"
16+
},
1417
"overrides": [
1518
{
1619
"files": ["src/**/*.{js,ts,jsx,tsx}"]

gui/src/components/StepContainer/AcceptRejectAllButtons.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export default function AcceptRejectAllButtons({
3838
<button
3939
className="flex cursor-pointer items-center border-none bg-transparent px-2 py-1 text-xs text-gray-300 opacity-80 hover:opacity-100 hover:brightness-125"
4040
onClick={() => handleAcceptOrReject("rejectDiff")}
41+
data-testid="edit-reject-button"
4142
>
4243
<XMarkIcon className="mr-1 h-4 w-4 text-red-600" />
4344
{isSingleRangeEdit ? (
@@ -53,6 +54,7 @@ export default function AcceptRejectAllButtons({
5354
<button
5455
className="flex cursor-pointer items-center border-none bg-transparent px-2 py-1 text-xs text-gray-300 opacity-80 hover:opacity-100 hover:brightness-125"
5556
onClick={() => handleAcceptOrReject("acceptDiff")}
57+
data-testid="edit-accept-button"
5658
>
5759
<CheckIcon className="mr-1 h-4 w-4 text-green-600" />
5860
{isSingleRangeEdit ? (

0 commit comments

Comments
 (0)