Skip to content

Commit f6b0043

Browse files
author
Venya Sharma
committed
Add LSP4Jakarta diagnostic + quick fix tests for Maven and Gradle (#125)
1. Added MavenTestLSPRestSnippetAndDiagnostic.ts and the Gradle equivalent to test the rest_class snippet, the "Only public methods can be exposed as resource methods" diagnostic, and the "Make method public" quick fix. 2. Added empty TestRest.java fixtures for both projects (the tests fill and reset them each run). 3. Added a JAX-RS dependency to the Maven pom so the rest_class snippet populates. 4. Added the init-project setup to the existing test files so they can be run individually.
1 parent a2365e2 commit f6b0043

9 files changed

Lines changed: 494 additions & 6 deletions

File tree

src/test/GradleTestDevModeActions.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Copyright IBM Corp. 2023, 2026
44
*/
55
import { expect } from 'chai';
6-
import { DefaultTreeItem, EditorView, InputBox, SideBarView, ViewSection, VSBrowser, Workbench } from 'vscode-extension-tester';
6+
import { DefaultTreeItem, EditorView, InputBox, SideBarView, ViewSection, VSBrowser, WebDriver, Workbench } from 'vscode-extension-tester';
77
import * as utils from './utils/testUtils';
88
import * as constants from './definitions/constants';
99
import { logger } from './utils/testLogger';
@@ -14,10 +14,13 @@ describe('Devmode action tests for Gradle Project', () => {
1414
let section: ViewSection;
1515
let item: DefaultTreeItem;
1616
let tabs: string[];
17+
let driver: WebDriver;
1718

1819
before(async function() {
1920
this.timeout(30000);
2021
// Wait for workbench to be ready
22+
driver = VSBrowser.instance.driver;
23+
await VSBrowser.instance.openResources(utils.getGradleProjectPath());
2124
await VSBrowser.instance.waitForWorkbench();
2225
sidebar = new SideBarView();
2326
});

src/test/GradleTestLSPHover.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Copyright IBM Corp. 2026
44
*/
55
import { expect } from 'chai';
6-
import { EditorView, TextEditor, VSBrowser, Workbench } from 'vscode-extension-tester';
6+
import { EditorView, TextEditor, VSBrowser, WebDriver, Workbench } from 'vscode-extension-tester';
77
import * as utils from './utils/testUtils';
88
import { logger } from './utils/testLogger';
99
import * as path from 'path';
@@ -12,11 +12,15 @@ describe('LSP Hover tests for Gradle Project', () => {
1212
let editorView: EditorView;
1313
let editor: TextEditor;
1414
let wait: any;
15+
let driver: WebDriver;
1516

1617
before(async function() {
1718
this.timeout(60000);
1819
logger.info('Setting up Gradle LSP Hover tests');
1920

21+
driver = VSBrowser.instance.driver;
22+
await VSBrowser.instance.openResources(utils.getGradleProjectPath());
23+
2024
// Wait for workbench to be ready
2125
await VSBrowser.instance.waitForWorkbench();
2226
editorView = new EditorView();
Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
2+
/*
3+
* IBM Confidential
4+
* Copyright IBM Corp. 2026
5+
*/
6+
import { expect } from 'chai';
7+
import { EditorView, TextEditor, VSBrowser, Workbench, WebDriver, BottomBarPanel, MarkerType, Key, By } from 'vscode-extension-tester';
8+
import * as utils from './utils/testUtils';
9+
import { logger } from './utils/testLogger';
10+
import * as path from 'path';
11+
12+
describe('Rest Class Snippet Test for Gradle Project', () => {
13+
let editorView: EditorView;
14+
let javaEditor: TextEditor;
15+
let wait: any;
16+
let driver: WebDriver;
17+
18+
const testRestPath = path.resolve(
19+
utils.getGradleProjectPath(),
20+
'src', 'main', 'java', 'test', 'gradle', 'liberty', 'web', 'app',
21+
'TestRest.java'
22+
);
23+
24+
before(async function() {
25+
this.timeout(60000);
26+
logger.info('Setting up rest_class snippet test');
27+
28+
driver = VSBrowser.instance.driver;
29+
await VSBrowser.instance.openResources(utils.getGradleProjectPath());
30+
31+
// Wait for workbench to be ready
32+
await VSBrowser.instance.waitForWorkbench();
33+
editorView = new EditorView();
34+
wait = utils.getWaitHelper();
35+
36+
// Open the file
37+
await VSBrowser.instance.openResources(testRestPath, async () => {
38+
await wait.sleep(3000);
39+
});
40+
javaEditor = await editorView.openEditor('TestRest.java') as TextEditor;
41+
});
42+
43+
afterEach(async function() {
44+
// Take screenshot on failure but don't close editor
45+
if (this.currentTest?.state === 'failed') {
46+
const driver = VSBrowser.instance.driver;
47+
const screenshot = await driver.takeScreenshot();
48+
logger.error(`Test failed: ${this.currentTest.title}`);
49+
}
50+
});
51+
52+
after(async function() {
53+
this.timeout(10000); // Increase timeout for cleanup operations
54+
// Close editor after all tests complete
55+
try {
56+
if(javaEditor){
57+
await javaEditor.setText('');
58+
await javaEditor.save();
59+
logger.info('Reset TestRest.java to empty after test')
60+
61+
}
62+
} catch (error){
63+
logger.error('Failed to reset TestRest.java ', error);
64+
}
65+
try {
66+
await editorView.closeAllEditors();
67+
logger.info('Closed all editors after test suite');
68+
} catch (error) {
69+
logger.error('Failed to close editors in after hook', error);
70+
}
71+
72+
utils.copyScreenshotsToProjectFolder('gradle');
73+
});
74+
75+
it('LSP4Jakarta Language Server should initialize', async function() {
76+
this.timeout(60000);
77+
logger.testStart('LSP4Jakarta Language Server should initialize');
78+
79+
try {
80+
await utils.waitForLanguageServerInit(
81+
'Language Support for Jakarta EE',
82+
'Initializing Jakarta EE server',
83+
60
84+
);
85+
logger.testComplete('LSP4Jakarta Language Server initialized successfully');
86+
} catch (error) {
87+
logger.testFailed('LSP4Jakarta Language Server should initialize', error);
88+
throw error;
89+
}
90+
});
91+
92+
it('rest_class snippet populates correct REST class', async function () {
93+
this.timeout(275000);
94+
logger.testStart('rest_class snippet inserts correct REST class');
95+
96+
// at the top of the rest_class snippet test, before positioning the cursor
97+
await javaEditor.setText('');
98+
await javaEditor.save();
99+
await wait.sleep(1500); // let any auto-stub settle, then confirm
100+
const check = await javaEditor.getText();
101+
logger.info('Buffer before snippet: ' + JSON.stringify(check));
102+
103+
try {
104+
logger.step(1, 'Positioning cursor for snippet insertion');
105+
// Position cursor at end of file
106+
const lastLine = (await javaEditor.getText()).split('\n').length;
107+
await javaEditor.setCursor(lastLine - 1, 1);
108+
109+
logger.step(2, 'Typing "rest" to trigger snippet');
110+
await javaEditor.typeText('rest');
111+
logger.stepSuccess(2, 'Typed "rest"');
112+
113+
logger.step(3, 'Opening content assist');
114+
const assist = await javaEditor.toggleContentAssist(true);
115+
if (assist) {
116+
logger.step(4,'Selecting rest_class snippet');
117+
await assist.select('rest_class');
118+
await new Promise(res => setTimeout(res, 600)); // 300–800ms
119+
logger.stepSuccess(4, 'rest_class snippet selected');
120+
}
121+
await javaEditor.toggleContentAssist(false);
122+
123+
logger.step(5, 'Verifying snippet insertion');
124+
const codeInsertion = await javaEditor.getText();
125+
logger.info('Inserted code snapshot: ' + codeInsertion);
126+
expect(codeInsertion).to.include('@GET')
127+
expect(codeInsertion).to.include('methodname');
128+
logger.stepSuccess(5, 'Snippet rest_class was inserted correctly');
129+
130+
logger.testComplete('rest_class snippet inserts correct REST class');
131+
} catch (error) {
132+
logger.testFailed('rest_class snippet inserts correct REST class', error);
133+
throw error;
134+
}
135+
});
136+
it('Show that private @GET method displays diagnostic and quick fix removes it ', async function () {
137+
this.timeout(90000);
138+
logger.testStart('Diagnostic for a private @GET method and quick fix clears it');
139+
try {
140+
// Find the method with @GET and change it to private
141+
let lineNum = await javaEditor.getLineOfText('methodname');
142+
if (lineNum < 1) throw new Error('Could not find the methodname line');
143+
const oldLine = await javaEditor.getTextAtLine(lineNum);
144+
const newLine = oldLine.replace("public", "private");
145+
await javaEditor.setTextAtLine(lineNum, newLine);
146+
147+
// Save file and wait for reanalysis
148+
await javaEditor.save();
149+
await wait.sleep(500);
150+
151+
// Open problems view
152+
const bottomBar = new BottomBarPanel();
153+
await bottomBar.toggle(true);
154+
let problemsView = await bottomBar.openProblemsView();
155+
let markers = await problemsView.getAllVisibleMarkers(MarkerType.Any);
156+
157+
// Check if the marker is present
158+
let found = false;
159+
for (const marker of markers) {
160+
const text = await marker.getText();
161+
// Check if text contains your diagnostic message
162+
if(text.includes('Only public methods can be exposed as resource methods.')){
163+
found = true;
164+
break;
165+
}
166+
}
167+
expect(found).to.be.true;
168+
logger.testComplete('Diagnostic shows for private @GET method');
169+
170+
// Quick fix implementation to get rid of diagnostic
171+
// Re-find line and place cursor on "methodname()"
172+
const buffer = await javaEditor.getText();
173+
logger.info('Buffer before quick fix: ' + JSON.stringify(buffer));
174+
175+
// Get column on the method name
176+
await javaEditor.selectText('methodname');
177+
await wait.sleep(300);
178+
179+
// Open the quick-fix menu with Cmd+. (Mac) / Ctrl+. (Linux/Windows)
180+
const modKey = process.platform === 'darwin' ? Key.COMMAND : Key.CONTROL;
181+
await driver.actions().keyDown(modKey).sendKeys('.').keyUp(modKey).perform();
182+
await wait.sleep(2000);
183+
184+
// Click on the option to make the method public within the quick-fixes options
185+
const options = await driver.findElements(By.css('.action-widget .action-list-item, .action-widget .monaco-list-row'));
186+
let clicked = false;
187+
for (const opt of options) {
188+
const text = await opt.getText();
189+
logger.info('OPTION: ' + JSON.stringify(text));
190+
if (text.toLowerCase().includes('make method public')) {
191+
await driver.executeScript('arguments[0].click();', opt);
192+
clicked = true;
193+
break;
194+
}
195+
}
196+
if (!clicked) {
197+
await driver.actions().sendKeys(Key.ESCAPE).perform(); // close menu cleanly
198+
throw new Error('No "make public" quick fix was offered — see OPTION logs above');
199+
}
200+
201+
await wait.sleep(3000);
202+
await javaEditor.save();
203+
await wait.sleep(5000);
204+
205+
// Check quick fix was implemented at correct line number
206+
const after = await javaEditor.getText();
207+
logger.info('Buffer after quick fix: ' + JSON.stringify(after));
208+
expect(after).to.include('public String methodname');
209+
210+
problemsView = await bottomBar.openProblemsView();
211+
markers = await problemsView.getAllVisibleMarkers(MarkerType.Any);
212+
213+
// Check if the marker is present
214+
let stillPresent = false;
215+
for (const marker of markers) {
216+
const text = await marker.getText();
217+
// Check if text contains diagnostic message
218+
if(text.includes('Only public methods can be exposed as resource methods.')){
219+
stillPresent = true;
220+
break;
221+
}
222+
}
223+
expect(stillPresent).to.be.false;
224+
logger.testComplete('Diagnostic no longer shows for public @GET method as expected');
225+
226+
} catch (error) {
227+
logger.testFailed('Diagnostic/quick-fix test flow failed', error);
228+
throw error;
229+
}
230+
231+
});
232+
});
233+

src/test/MavenTestDevModeActions.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Copyright IBM Corp. 2023, 2026
44
*/
55
import { expect } from 'chai';
6-
import { DefaultTreeItem, EditorView, SideBarView, ViewItem, ViewSection, VSBrowser, Workbench } from 'vscode-extension-tester';
6+
import { DefaultTreeItem, EditorView, SideBarView, ViewItem, ViewSection, VSBrowser, Workbench, WebDriver } from 'vscode-extension-tester';
77
import * as utils from './utils/testUtils';
88
import * as constants from './definitions/constants';
99
import { logger } from './utils/testLogger';
@@ -15,11 +15,15 @@ describe('Devmode action tests for Maven Project', () => {
1515
let menu: ViewItem[];
1616
let item: DefaultTreeItem;
1717
let tabs: string[];
18+
let driver: WebDriver;
1819

1920
before(async function() {
2021
this.timeout(30000);
21-
// Wait for workbench to be ready
22+
23+
driver = VSBrowser.instance.driver;
24+
await VSBrowser.instance.openResources(utils.getMvnProjectPath());
2225
await VSBrowser.instance.waitForWorkbench();
26+
2327
sidebar = new SideBarView();
2428
});
2529

src/test/MavenTestLSPHover.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Copyright IBM Corp. 2026
44
*/
55
import { expect } from 'chai';
6-
import { EditorView, TextEditor, VSBrowser, Workbench } from 'vscode-extension-tester';
6+
import { EditorView, TextEditor, VSBrowser, Workbench, WebDriver } from 'vscode-extension-tester';
77
import * as utils from './utils/testUtils';
88
import { logger } from './utils/testLogger';
99
import * as path from 'path';
@@ -12,9 +12,13 @@ describe('LSP Hover tests for Maven Project', () => {
1212
let editorView: EditorView;
1313
let editor: TextEditor;
1414
let wait: any;
15+
let driver: WebDriver;
16+
1517

1618
before(async function() {
1719
this.timeout(60000);
20+
driver = VSBrowser.instance.driver;
21+
await VSBrowser.instance.openResources(utils.getMvnProjectPath());
1822
logger.info('Setting up Maven LSP Hover tests');
1923

2024
// Wait for workbench to be ready
@@ -214,4 +218,5 @@ describe('LSP Hover tests for Maven Project', () => {
214218

215219
});
216220

217-
// Made with Bob
221+
222+

0 commit comments

Comments
 (0)