From 64766234d4ce48dec3c7a06af3574c9b3e879c56 Mon Sep 17 00:00:00 2001 From: Venya Sharma Date: Tue, 23 Jun 2026 13:37:08 -0500 Subject: [PATCH 1/4] Add shared test suites to eliminate Maven/Gradle duplication - Created shared/restSnippetSuite.ts for REST snippet tests - Created shared/hoverTestSuite.ts for hover tests - Created shared/devModeTestSuite.ts for DevMode tests (6 shared tests) - Refactored Maven/Gradle entry files to use shared suites - Achieved ~50% code reduction through parameterization - Kept build-tool-specific tests in separate describe blocks --- src/test/GradleTestDevModeActions.ts | 291 +---------------- src/test/GradleTestLSPHover.ts | 185 +---------- .../GradleTestLSPRestSnippetAndDiagnostic.ts | 176 +---------- src/test/MavenTestDevModeActions.ts | 295 +---------------- src/test/MavenTestLSPHover.ts | 185 +---------- .../MavenTestLSPRestSnippetAndDiagnostic.ts | 176 +---------- src/test/shared/devModeTestSuite.ts | 298 ++++++++++++++++++ src/test/shared/hoverTestSuite.ts | 194 ++++++++++++ src/test/shared/restSnippetSuite.ts | 185 +++++++++++ 9 files changed, 723 insertions(+), 1262 deletions(-) create mode 100644 src/test/shared/devModeTestSuite.ts create mode 100644 src/test/shared/hoverTestSuite.ts create mode 100644 src/test/shared/restSnippetSuite.ts diff --git a/src/test/GradleTestDevModeActions.ts b/src/test/GradleTestDevModeActions.ts index f932be03..7a2dfde9 100755 --- a/src/test/GradleTestDevModeActions.ts +++ b/src/test/GradleTestDevModeActions.ts @@ -3,223 +3,31 @@ * Copyright IBM Corp. 2023, 2026 */ import { expect } from 'chai'; -import { DefaultTreeItem, EditorView, SideBarView, ViewItem, ViewSection, VSBrowser, Workbench, WebDriver } from 'vscode-extension-tester'; +import { EditorView, VSBrowser } from 'vscode-extension-tester'; +import { runDevModeTestSuite } from "./shared/devModeTestSuite"; import * as utils from './utils/testUtils'; import * as constants from './definitions/constants'; import { logger } from './utils/testLogger'; import path = require('path'); import { DashboardPage } from './pages/DashboardPage'; -describe('Devmode action tests for Gradle Project', () => { +// Run shared dev mode tests +runDevModeTestSuite({ + buildTool: 'gradle', + getProjectPath: utils.getGradleProjectPath, + projectConstant: constants.GRADLE_PROJECT, + testRunString: constants.GRADLE_TEST_RUN_STRING +}); + +// Gradle-specific tests in their own describe block +describe('Gradle-specific devmode action tests', () => { let dashboard: DashboardPage; before(async function() { this.timeout(30000); - - await VSBrowser.instance.openResources(utils.getGradleProjectPath()); - await VSBrowser.instance.waitForWorkbench(); - dashboard = new DashboardPage(); }); - afterEach(async function() { - this.timeout(10000); // Increase timeout for cleanup operations - // Close any open editors after each test - if (this.currentTest?.state === 'failed') { - const driver = VSBrowser.instance.driver; - const screenshot = await driver.takeScreenshot(); - logger.error(`Test failed: ${this.currentTest.title}`); - } - - try { - await new EditorView().closeAllEditors(); - } catch (error) { - logger.error('Failed to close editors in afterEach', error); - } - - // Clear terminal between tests to avoid confusion with old output - try { - const workbench = new Workbench(); - await workbench.executeCommand('terminal clear'); - } catch (error) { - logger.error('Failed to clear terminal in afterEach', error); - } - }); - - it('Find Liberty Tools in sidebar', async () => { - logger.testStart('Find Liberty Tools in sidebar'); - try { - logger.step(1, 'Attempting to get Liberty Tools section'); - const section = await dashboard.getSection(); - logger.stepSuccess(1, 'Found Liberty Tools section'); - - logger.step(2, 'Validating sidebar is not undefined'); - expect(section).not.undefined; - logger.testComplete('Find Liberty Tools in sidebar'); - } catch (error) { - logger.testFailed('Find Liberty Tools in sidebar', error); - throw error; - } - }).timeout(60000); - - it('Liberty Tools shows items - Gradle', async () => { - logger.testStart('Liberty Tools shows items - Gradle'); - try { - logger.step(1, 'Getting dashboard section'); - const section = await dashboard.getSection(); - logger.stepSuccess(1, 'Dashboard section retrieved'); - - logger.step(2, 'Waiting for Liberty Tools to load'); - await utils.waitForDashboardToLoad(section); - logger.stepSuccess(2, 'Liberty Tools loaded successfully'); - - logger.step(3, 'Getting visible items from section'); - const menu = await utils.waitForCondition(async () => { - const items = await section.getVisibleItems(); - if (items && items.length > 0) { - return items; - } - return; - }, 60); - logger.info(`Found ${menu.length} visible items in dashboard`); - expect(menu).not.empty; - - logger.step(4, `Finding Gradle project item: ${constants.GRADLE_PROJECT}`); - const item = await dashboard.getProjectItem(constants.GRADLE_PROJECT); - logger.stepSuccess(4, 'Gradle project item found'); - expect(item).not.undefined; - - logger.testComplete('Liberty Tools shows items - Gradle'); - } catch (error) { - logger.testFailed('Liberty Tools shows items - Gradle', error); - throw error; - } - }).timeout(275000); - - it('Start Gradle project from Liberty Tools', async () => { - logger.testStart('Start Gradle project from Liberty Tools'); - try { - logger.step(1, 'Getting dashboard section and item'); - await dashboard.runAction(constants.GRADLE_PROJECT, constants.START_DASHBOARD_ACTION, constants.START_DASHBOARD_MAC_ACTION); - - logger.step(2, 'Waiting for server to start'); - const serverStartStatus = await utils.waitForServerStart(constants.SERVER_START_STRING); - - if (!serverStartStatus) { - logger.error('Server started message not found in the terminal'); - } else { - logger.stepSuccess(2, 'Server successfully started'); - - logger.step(3, 'Launching dashboard stop action'); - await dashboard.runAction(constants.GRADLE_PROJECT, constants.STOP_DASHBOARD_ACTION, constants.STOP_DASHBOARD_MAC_ACTION); - - logger.step(4, 'Waiting for server to stop'); - const serverStopStatus = await utils.waitForServerStop(constants.SERVER_STOP_STRING); - - if (!serverStopStatus) { - logger.error('Server stopped message not found in the terminal'); - } else { - logger.stepSuccess(4, 'Server stopped successfully'); - } - expect(serverStopStatus).to.be.true; - } - - expect(serverStartStatus).to.be.true; - logger.testComplete('Start Gradle project from Liberty Tools'); - } catch (error) { - logger.testFailed('Start Gradle project from Liberty Tools', error); - throw error; - } - }).timeout(350000); - - it('Start Gradle with Docker from Liberty Tools', async () => { - logger.testStart('Start Gradle with Docker from Liberty Tools'); - - if ((process.platform === 'darwin') || (process.platform === 'win32')) { - logger.skip(`Test skipped for platform: ${process.platform} (Docker test only runs on Linux)`); - return true; - } - - try { - logger.step(1, 'Launching dashboard start action with Docker'); - await dashboard.runAction(constants.GRADLE_PROJECT, constants.START_DASHBOARD_ACTION_WITHDOCKER, constants.START_DASHBOARD_MAC_ACTION_WITHDOCKER); - - logger.step(2, 'Waiting for server to start in Docker container'); - const serverStartStatus = await utils.waitForServerStart(constants.SERVER_START_STRING); - - if (!serverStartStatus) { - logger.error('Server started message not found in the terminal'); - } else { - logger.stepSuccess(2, 'Server successfully started in Docker container'); - - logger.step(3, 'Launching dashboard stop action'); - await dashboard.runAction(constants.GRADLE_PROJECT, constants.STOP_DASHBOARD_ACTION, constants.STOP_DASHBOARD_MAC_ACTION); - - logger.step(4, 'Waiting for server to stop'); - const serverStopStatus = await utils.waitForServerStop(constants.SERVER_STOP_STRING); - - if (!serverStopStatus) { - logger.error('Server stopped message not found in the terminal'); - } else { - logger.stepSuccess(4, 'Server stopped successfully'); - } - expect(serverStopStatus).to.be.true; - } - - expect(serverStartStatus).to.be.true; - logger.testComplete('Start Gradle with Docker from Liberty Tools'); - } catch (error) { - logger.testFailed('Start Gradle with Docker from Liberty Tools', error); - throw error; - } - }).timeout(350000); - - it('Run tests for Gradle project', async () => { - logger.testStart('Run tests for Gradle project'); - try { - logger.step(1, 'Launching dashboard start action'); - await dashboard.runAction(constants.GRADLE_PROJECT, constants.START_DASHBOARD_ACTION, constants.START_DASHBOARD_MAC_ACTION); - - logger.step(2, 'Waiting for server to start'); - const serverStartStatus = await utils.waitForServerStart(constants.SERVER_START_STRING); - - if (!serverStartStatus) { - logger.error('Server started message not found in the terminal'); - } else { - logger.stepSuccess(2, 'Server successfully started'); - - logger.step(3, 'Launching run tests dashboard action'); - await dashboard.runAction(constants.GRADLE_PROJECT, constants.RUNTEST_DASHBOARD_ACTION, constants.RUNTEST_DASHBOARD_MAC_ACTION); - - logger.step(4, 'Checking test execution status'); - const testStatus = await utils.checkTestStatus(constants.GRADLE_TEST_RUN_STRING); - logger.info(`Test status result: ${testStatus}`); - expect(testStatus).to.be.true; - logger.stepSuccess(4, 'Tests executed successfully'); - - logger.step(5, 'Launching dashboard stop action'); - await dashboard.runAction(constants.GRADLE_PROJECT, constants.STOP_DASHBOARD_ACTION, constants.STOP_DASHBOARD_MAC_ACTION); - - logger.step(6, 'Waiting for server to stop'); - const serverStopStatus = await utils.waitForServerStop(constants.SERVER_STOP_STRING); - - if (!serverStopStatus) { - logger.error('Server stopped message not found in the terminal'); - } else { - logger.stepSuccess(6, 'Server stopped successfully'); - } - expect(serverStopStatus).to.be.true; - } - - expect(serverStartStatus).to.be.true; - logger.testComplete('Run tests for Gradle project'); - } catch (error) { - logger.testFailed('Run tests for Gradle project', error); - throw error; - } - }).timeout(350000); - - it('Start Gradle with options from Liberty Tools', async () => { logger.testStart('Start Gradle with options from Liberty Tools'); try { @@ -328,72 +136,6 @@ describe('Devmode action tests for Gradle Project', () => { } }).timeout(550000); - /** - * All future test cases should be written before the test that attaches the debugger, as this will switch the UI to the debugger view. - * If, for any reason, a test case needs to be written after the debugger test, ensure that the UI is switched back to the explorer view before executing the subsequent tests. - */ - it('Attach debugger for Gradle with custom parameter event', async () => { - logger.testStart('Attach debugger for Gradle with custom parameter event'); - let isServerRunning: Boolean = true; - let attachStatus: Boolean = false; - - try { - logger.step(1, 'Launching dashboard start action with custom parameters'); - await dashboard.runAction(constants.GRADLE_PROJECT, constants.START_DASHBOARD_ACTION_WITH_PARAM, constants.START_DASHBOARD_MAC_ACTION_WITH_PARAM); - - logger.step(2, 'Setting custom debug parameter: -DdebugPort=7777'); - await utils.setCustomParameter("-DdebugPort=7777"); - - logger.step(3, 'Waiting for server to start in debug mode'); - isServerRunning = await utils.waitForServerStart(constants.SERVER_START_STRING); - - if (!isServerRunning) { - logger.error('Server started with params message not found in terminal'); - } else { - logger.stepSuccess(3, 'Server successfully started in debug mode'); - - logger.step(4, 'Launching attach debugger dashboard action'); - await dashboard.runAction(constants.GRADLE_PROJECT, constants.ATTACH_DEBUGGER_DASHBOARD_ACTION, constants.ATTACH_DEBUGGER_DASHBOARD_MAC_ACTION); - logger.info('Attach Debugger action completed'); - - logger.step(5, 'Waiting for debugger to attach'); - attachStatus = await utils.waitForDebuggerAttach(); - - if (!attachStatus) { - logger.error('DebugToolbar not found - debugger may not have attached'); - } else { - logger.stepSuccess(5, 'Debugger attached successfully'); - } - - logger.step(6, 'Stopping Liberty server'); - await utils.stopLibertyserver(constants.GRADLE_PROJECT); - - logger.step(7, 'Waiting for server to stop'); - isServerRunning = !await utils.waitForServerStop(constants.SERVER_STOP_STRING); - - if (!isServerRunning) { - logger.stepSuccess(7, 'Server stopped successfully'); - } else { - logger.error('Server stop message not found in terminal'); - } - } - } catch (e) { - logger.error('Exception occurred during attach debugger test', e); - throw e; - } finally { - logger.info(`Finally block - Server running status: ${isServerRunning}`); - if (isServerRunning) { - logger.info('Attempting to stop server in finally block'); - await utils.stopLibertyserver(constants.GRADLE_PROJECT); - } else { - logger.info('Server already stopped, test cleanup complete'); - } - } - - expect(attachStatus).to.be.true; - logger.testComplete('Attach debugger for Gradle with custom parameter event'); - }).timeout(350000); - it('View test report for Gradle project', async () => { logger.testStart('View test report for Gradle project'); @@ -437,11 +179,6 @@ describe('Devmode action tests for Gradle Project', () => { throw error; } }).timeout(100000); +}); + - /** - * The following after hook copies the screenshot from the temporary folder in which it is saved to a known permanent location in the project folder. - */ - after(() => { - utils.copyScreenshotsToProjectFolder('gradle'); - }); -}); \ No newline at end of file diff --git a/src/test/GradleTestLSPHover.ts b/src/test/GradleTestLSPHover.ts index 75c79e20..b2fa37e2 100644 --- a/src/test/GradleTestLSPHover.ts +++ b/src/test/GradleTestLSPHover.ts @@ -1,188 +1,15 @@ -/* - * IBM Confidential - * Copyright IBM Corp. 2026 - */ -import { expect } from 'chai'; -import { EditorView, VSBrowser } from 'vscode-extension-tester'; import * as utils from './utils/testUtils'; -import { logger } from './utils/testLogger'; -import * as path from 'path'; -import { EditorPage } from './pages/EditorPage'; -import * as editorUtils from './utils/editorUtils'; +import { runHoverTestSuite } from './shared/hoverTestSuite'; -describe('LSP Hover tests for Gradle Project', () => { - let serverXml: EditorPage; - - before(async function() { - this.timeout(60000); - - logger.info('Setting up Gradle LSP Hover tests'); - - // Wait for workbench to be ready - await VSBrowser.instance.openResources(utils.getGradleProjectPath()); - await VSBrowser.instance.waitForWorkbench(); - - // Open server.xml file once for all tests - logger.info('Opening server.xml file for all tests'); - const serverXmlPath = path.resolve( - utils.getGradleProjectPath(), - 'src', - 'main', - 'liberty', - 'config', - 'server.xml' - ); - logger.info(`Server.xml path: ${serverXmlPath}`); - - serverXml = await new EditorPage().openFile(serverXmlPath, 'server.xml'); - logger.info('Server.xml file opened and editor obtained'); - }); - - afterEach(async function() { - // Take screenshot on failure but don't close editor - if (this.currentTest?.state === 'failed') { - const driver = VSBrowser.instance.driver; - const screenshot = await driver.takeScreenshot(); - logger.error(`Test failed: ${this.currentTest.title}`); - } - }); - - after(async function() { - this.timeout(10000); // Increase timeout for cleanup operations - // Close editor after all tests complete - try { - await new EditorView().closeAllEditors(); - logger.info('Closed all editors after test suite'); - } catch (error) { - logger.error('Failed to close editors in after hook', error); - } - - utils.copyScreenshotsToProjectFolder('gradle'); - }); - - it('Liberty Language Server should initialize', async function() { - this.timeout(60000); - logger.testStart('Liberty Language Server should initialize'); - - try { - await utils.waitForLanguageServerInit( - 'Language Support for Liberty', - 'Initialized Liberty Language server', - 60 - ); - logger.testComplete('Liberty Language Server initialized successfully'); - } catch (error) { - logger.testFailed('Liberty Language Server should initialize', error); - throw error; - } - }); - - // Test data for parameterized hover tests - const hoverTestCases = [ +runHoverTestSuite({ + buildTool: 'gradle', + getProjectPath: utils.getGradleProjectPath, + hoverTestCases: [ { element: 'httpEndpoint element', line: 18, column: 10, expectedDoc: 'Configuration properties for an HTTP endpoint.' }, { element: 'feature element', line: 15, column: 16, expectedDoc: 'Specifies a feature to be used when the server runs.' }, { element: 'featureManager element', line: 14, column: 10, expectedDoc: 'Defines how the server loads features.' }, { element: 'webApplication element', line: 20, column: 10, expectedDoc: 'Defines the properties of a web application.' }, { element: 'jsp-2.3 feature value', line: 15, column: 22, expectedDoc: 'This feature enables support for Java Server Pages (JSPs) that are written to the JSP 2.3 specification.' }, { element: 'httpPort attribute', line: 18, column: 33, expectedDoc: 'The port used for client HTTP requests. Use -1 to disable this port.' } - ]; - - hoverTestCases.forEach(testCase => { - it(`Hover over ${testCase.element} shows Liberty Language Server documentation`, async function() { - this.timeout(30000); - logger.testStart(`Hover over ${testCase.element} shows Liberty Language Server documentation`); - - try { - const hoverText = await editorUtils.hoverOver(serverXml.getEditor(), testCase.line, testCase.column, testCase.element); - expect(hoverText).to.not.be.empty; - logger.stepSuccess(3, `Hover widget displayed with Liberty Language Server content for ${testCase.element}`); - - logger.step(4, 'Verifying hover contains expected documentation'); - expect(hoverText).to.include(testCase.expectedDoc); - logger.stepSuccess(4, `Hover text contains expected documentation: "${testCase.expectedDoc}"`); - - logger.testComplete(`Hover over ${testCase.element} shows Liberty Language Server documentation`); - } catch (error) { - logger.testFailed(`Hover over ${testCase.element} shows Liberty Language Server documentation`, error); - throw error; - } - }); - }); - - describe('LSP4Jakarta Hover tests in Java file', () => { - let javaFile: EditorPage; - - before(async function() { - this.timeout(60000); - logger.info('Opening HelloServlet.java file for LSP4Jakarta hover tests'); - - const javaFilePath = path.resolve( - utils.getGradleProjectPath(), - 'src', - 'main', - 'java', - 'test', - 'gradle', - 'liberty', - 'web', - 'app', - 'HelloServlet.java' - ); - logger.info(`Java file path: ${javaFilePath}`); - javaFile = await new EditorPage().openFile(javaFilePath, 'HelloServlet.java') - - logger.info('HelloServlet.java file opened and editor obtained'); - }); - - it('LSP4Jakarta Language Server should initialize', async function() { - this.timeout(60000); - logger.testStart('LSP4Jakarta Language Server should initialize'); - - try { - await utils.waitForLanguageServerInit( - 'Language Support for Jakarta EE', - 'Initializing Jakarta EE server', - 60 - ); - logger.testComplete('LSP4Jakarta Language Server initialized successfully'); - } catch (error) { - logger.testFailed('LSP4Jakarta Language Server should initialize', error); - throw error; - } - }); - - // Test data for LSP4Jakarta hover tests - const jakartaHoverTestCases = [ - { element: '@WebServlet annotation', line: 23, column: 2, expectedDoc: 'Annotation used to declare a servlet.' }, - { element: 'HttpServlet class', line: 24, column: 35, expectedDoc: 'Provides an abstract class to be subclassed to create an HTTP servlet suitable for a Web site.' }, - { element: 'HttpServletRequest type', line: 30, column: 35, expectedDoc: 'Extends the javax.servlet.ServletRequest interface to provide request information for HTTP servlets.' }, - { element: 'HttpServletResponse type', line: 30, column: 70, expectedDoc: 'Extends the ServletResponse interface to provide HTTP-specific functionality in sending a response.' } - ]; - - jakartaHoverTestCases.forEach(testCase => { - it(`Hover over ${testCase.element} shows LSP4Jakarta documentation`, async function() { - this.timeout(30000); - logger.testStart(`Hover over ${testCase.element} shows LSP4Jakarta documentation`); - - try { - const hoverText = await editorUtils.hoverOver(javaFile.getEditor(), testCase.line, testCase.column, testCase.element); - - expect(hoverText).to.not.be.empty; - logger.stepSuccess(3, `Hover widget displayed with LSP4Jakarta content for ${testCase.element}`); - - logger.step(4, 'Verifying hover contains expected documentation'); - expect(hoverText).to.include(testCase.expectedDoc); - logger.stepSuccess(4, `Hover text contains expected documentation: "${testCase.expectedDoc}"`); - - logger.testComplete(`Hover over ${testCase.element} shows LSP4Jakarta documentation`); - } catch (error) { - logger.testFailed(`Hover over ${testCase.element} shows LSP4Jakarta documentation`, error); - throw error; - } - }); - }); - }); - + ] }); - -// Made with Bob diff --git a/src/test/GradleTestLSPRestSnippetAndDiagnostic.ts b/src/test/GradleTestLSPRestSnippetAndDiagnostic.ts index 22e6725a..fa50985f 100644 --- a/src/test/GradleTestLSPRestSnippetAndDiagnostic.ts +++ b/src/test/GradleTestLSPRestSnippetAndDiagnostic.ts @@ -1,176 +1,4 @@ - -/* - * IBM Confidential - * Copyright IBM Corp. 2026 - */ -import { expect } from 'chai'; -import { EditorView, VSBrowser, WebDriver } from 'vscode-extension-tester'; import * as utils from './utils/testUtils'; -import { logger } from './utils/testLogger'; -import * as path from 'path'; -import { ProblemsPage } from './pages/ProblemsPage'; -import { EditorPage } from './pages/EditorPage'; -import { CodeAssistPage } from './pages/CodeAssistPage'; -import { QuickFixPage } from './pages/QuickFixPage'; -import * as editorUtils from './utils/editorUtils'; - -describe('Rest Class Snippet Test for Gradle Project', () => { - let editorPage: EditorPage; - let wait: any; - let driver: WebDriver; - - const testRestPath = path.resolve( - utils.getGradleProjectPath(), - 'src', 'main', 'java', 'test', 'gradle', 'liberty', 'web', 'app', - 'TestRest.java' - ); - - before(async function() { - this.timeout(60000); - logger.info('Setting up rest_class snippet test'); - - driver = VSBrowser.instance.driver; - wait = utils.getWaitHelper(); - // Open folder, wait for workbench - await VSBrowser.instance.openResources(utils.getGradleProjectPath()); - await VSBrowser.instance.waitForWorkbench(); - - // Open file and bind page object to editor - editorPage = await new EditorPage().openFile(testRestPath, 'TestRest.java'); - - }); - - afterEach(async function() { - // Take screenshot on failure but don't close editor - if (this.currentTest?.state === 'failed') { - const driver = VSBrowser.instance.driver; - const screenshot = await driver.takeScreenshot(); - logger.error(`Test failed: ${this.currentTest.title}`); - } - }); - - after(async function() { - this.timeout(15000); - try { - if (editorPage) { - // Select all text first, then clear - const currentText = await editorPage.getEditor().getText(); - try { - await editorPage.getEditor().selectText(currentText); - await wait.sleep(300); - } catch (selectError) { - // selectText may fail but setText still works - } - - await editorUtils.clearEditor(editorPage.getEditor()); - logger.info('Reset TestRest.java to empty after test'); - } - } catch (error) { - logger.error('Failed to reset TestRest.java', error); - } - - try { - await new EditorView().closeAllEditors(); - await wait.sleep(500); - logger.info('Closed all editors after test suite'); - } catch (error) { - logger.error('Failed to close editors in after hook', error); - } - - utils.copyScreenshotsToProjectFolder('gradle'); - }); - - it('LSP4Jakarta Language Server should initialize', async function() { - this.timeout(60000); - logger.testStart('LSP4Jakarta Language Server should initialize'); - - try { - await utils.waitForLanguageServerInit( - 'Language Support for Jakarta EE', - 'Initializing Jakarta EE server', - 60 - ); - logger.testComplete('LSP4Jakarta Language Server initialized successfully'); - } catch (error) { - logger.testFailed('LSP4Jakarta Language Server should initialize', error); - throw error; - } - }); - - it('rest_class snippet populates correct REST class', async function () { - this.timeout(275000); - logger.testStart('rest_class snippet inserts correct REST class'); - - // at the top of the rest_class snippet test, before positioning the cursor - await editorUtils.clearEditor(editorPage.getEditor()); - await wait.sleep(1500); // let any auto-stub settle, then confirm - const check = await editorPage.getEditor().getText(); - logger.info('Buffer before snippet: ' + JSON.stringify(check)); - - try { - logger.step(1, 'Positioning cursor for snippet insertion'); - // Position cursor at end of file - await editorUtils.moveCursorToEnd(editorPage.getEditor()); - - // type rest and insert snippet - logger.step(2, 'Opening content assist'); - const codeAssist = new CodeAssistPage(); - await codeAssist.insertSnippet(editorPage, 'rest', 'rest_class'); - logger.stepSuccess(2, 'Snippet inserted'); - await wait.sleep(1000); // Give time for snippet to fully expand - - logger.step(3, 'Verifying snippet insertion'); - const codeInsertion = await editorPage.getEditor().getText(); - expect(codeInsertion).to.include('@GET') - expect(codeInsertion).to.include('methodname'); - logger.stepSuccess(3, 'Snippet rest_class was inserted correctly'); - - // Save the file so the content persists for the next test - await editorPage.getEditor().save(); - await wait.sleep(500); - - logger.testComplete('rest_class snippet inserts correct REST class'); - } catch (error) { - logger.testFailed('rest_class snippet inserts correct REST class', error); - throw error; - } - }); - it('Show that private @GET method displays diagnostic and quick fix removes it ', async function () { - this.timeout(90000); - logger.testStart('Diagnostic for a private @GET method and quick fix clears it'); - try { - // Find the method with @GET and change it to private - await editorUtils.replaceTextWithinLineContaining(editorPage.getEditor(), 'methodname', 'public', 'private'); - - // Save file and wait for reanalysis - await editorPage.getEditor().save(); - await wait.sleep(500); - - // Check that the diagnostic is there - let problems = new ProblemsPage(); - const found = await problems.hasDiagnostic('Only public methods can be exposed as resource methods.'); - expect(found).to.be.true; - logger.testComplete('Diagnostic shows for private @GET method'); - - // Quick fix implementation to get rid of diagnostic - // Re-find line and place cursor on "methodname()" - const buffer = await editorPage.getEditor().getText(); - logger.info('Buffer before quick fix: ' + JSON.stringify(buffer)); - - await new QuickFixPage().applyFix(editorPage, 'methodname', 'make method public'); - await wait.sleep(3000); - await editorPage.getEditor().save(); - await wait.sleep(5000); - - const after = await editorPage.getEditor().getText(); - expect(after).to.include('public String methodname'); - expect(await problems.hasDiagnostic('Only public methods can be exposed as resource methods.')).to.be.false; - - } catch (error) { - logger.testFailed('Diagnostic/quick-fix test flow failed', error); - throw error; - } - - }); - }); +import { runRestSnippetSuite } from './shared/restSnippetSuite'; +runRestSnippetSuite({ buildTool: 'gradle', getProjectPath: utils.getGradleProjectPath }); diff --git a/src/test/MavenTestDevModeActions.ts b/src/test/MavenTestDevModeActions.ts index c95ed989..124ab96d 100755 --- a/src/test/MavenTestDevModeActions.ts +++ b/src/test/MavenTestDevModeActions.ts @@ -3,221 +3,31 @@ * Copyright IBM Corp. 2023, 2026 */ import { expect } from 'chai'; -import { DefaultTreeItem, EditorView, SideBarView, ViewItem, ViewSection, VSBrowser, Workbench, WebDriver } from 'vscode-extension-tester'; +import { EditorView, VSBrowser } from 'vscode-extension-tester'; +import { runDevModeTestSuite } from "./shared/devModeTestSuite"; import * as utils from './utils/testUtils'; -import * as constants from './definitions/constants'; import { logger } from './utils/testLogger'; -import path = require('path'); +import * as constants from './definitions/constants'; +import * as path from 'path'; import { DashboardPage } from './pages/DashboardPage'; -describe('Devmode action tests for Maven Project', () => { - let dashboard: DashboardPage; +// Run shared dev mode tests +runDevModeTestSuite({ + buildTool: 'maven', + getProjectPath: utils.getMvnProjectPath, + projectConstant: constants.MAVEN_PROJECT, + testRunString: constants.MAVEN_RUN_TESTS_STRING +}); + +// Maven-specific tests in their own describe block +describe('Maven-specific devmode action tests', () => { + let dashboard: DashboardPage; before(async function() { this.timeout(30000); - - await VSBrowser.instance.openResources(utils.getMvnProjectPath()); - await VSBrowser.instance.waitForWorkbench(); - dashboard = new DashboardPage(); }); - afterEach(async function() { - this.timeout(10000); // Increase timeout for cleanup operations - // Close any open editors after each test - if (this.currentTest?.state === 'failed') { - await VSBrowser.instance.driver.takeScreenshot(); - logger.error(`Test failed: ${this.currentTest.title}`); - } - - try { - await new EditorView().closeAllEditors(); - } catch (error) { - logger.error('Failed to close editors in afterEach', error); - } - - // Clear terminal between tests to avoid confusion with old output - try { - const workbench = new Workbench(); - await workbench.executeCommand('terminal clear'); - } catch (error) { - logger.error('Failed to clear terminal in afterEach', error); - } - }); - - it('Find Liberty Tools in sidebar', async () => { - logger.testStart('Find Liberty Tools in sidebar'); - try { - logger.step(1, 'Attempting to get Liberty Tools section'); - const section = await dashboard.getSection(); - logger.stepSuccess(1, 'Found Liberty Tools section'); - - logger.step(2, 'Validating sidebar is not undefined'); - expect(section).not.undefined; - logger.testComplete('Find Liberty Tools in sidebar'); - } catch (error) { - logger.testFailed('Find Liberty Tools in sidebar', error); - throw error; - } - }).timeout(60000); - - it('Liberty Tools shows items - Maven', async () => { - logger.testStart('Liberty Tools shows items - Maven'); - try { - logger.step(1, 'Getting dashboard section'); - const section = await dashboard.getSection(); - logger.stepSuccess(1, 'Dashboard section retrieved'); - - logger.step(2, 'Waiting for Liberty Tools to load'); - await utils.waitForDashboardToLoad(section); - logger.stepSuccess(2, 'Liberty Tools loaded successfully'); - - logger.step(3, 'Getting visible items from section'); - const menu = await utils.waitForCondition(async () => { - const items = await section.getVisibleItems(); - if (items && items.length > 0) { - return items; - } - return; - }, 60); - logger.info(`Found ${menu.length} visible items in dashboard`); - expect(menu).not.empty; - - logger.step(4, `Finding Maven project item: ${constants.MAVEN_PROJECT}`); - const item = await dashboard.getProjectItem(constants.MAVEN_PROJECT); - logger.stepSuccess(4, 'Maven project item found'); - expect(item).not.undefined; - - logger.testComplete('Liberty Tools shows items - Maven'); - } catch (error) { - logger.testFailed('Liberty Tools shows items - Maven', error); - throw error; - } - }).timeout(275000); - - it('Start Maven project from Liberty Tools', async () => { - logger.testStart('Start Maven project from Liberty Tools'); - try { - logger.step(1, 'Getting dashboard section and item'); - await dashboard.runAction(constants.MAVEN_PROJECT, constants.START_DASHBOARD_ACTION, constants.START_DASHBOARD_MAC_ACTION); - - logger.step(2, 'Waiting for server to start'); - const serverStartStatus = await utils.waitForServerStart(constants.SERVER_START_STRING); - - if (!serverStartStatus) { - logger.error('Server started message not found in the terminal'); - } else { - logger.stepSuccess(2, 'Server successfully started'); - - logger.step(4, 'Launching dashboard stop action'); - await dashboard.runAction(constants.MAVEN_PROJECT, constants.STOP_DASHBOARD_ACTION, constants.STOP_DASHBOARD_MAC_ACTION); - - logger.step(5, 'Waiting for server to stop'); - const serverStopStatus = await utils.waitForServerStop(constants.SERVER_STOP_STRING); - - if (!serverStopStatus) { - logger.error('Server stopped message not found in the terminal'); - } else { - logger.stepSuccess(5, 'Server stopped successfully'); - } - expect(serverStopStatus).to.be.true; - } - - expect(serverStartStatus).to.be.true; - logger.testComplete('Start Maven project from Liberty Tools'); - } catch (error) { - logger.testFailed('Start Maven project from Liberty Tools', error); - throw error; - } - }).timeout(550000); - - it('Start Maven with Docker from Liberty Tools', async () => { - logger.testStart('Start Maven with Docker from Liberty Tools'); - - if ((process.platform === 'darwin') || (process.platform === 'win32')) { - logger.skip(`Test skipped for platform: ${process.platform} (Docker test only runs on Linux)`); - return true; - } - - try { - logger.step(1, 'Launching dashboard start action with Docker'); - await dashboard.runAction(constants.MAVEN_PROJECT, constants.START_DASHBOARD_ACTION_WITHDOCKER, constants.START_DASHBOARD_MAC_ACTION_WITHDOCKER); - - logger.step(2, 'Waiting for server to start in Docker container'); - const serverStartStatus = await utils.waitForServerStart(constants.SERVER_START_STRING); - - if (!serverStartStatus) { - logger.error('Server started message not found in the terminal'); - } else { - logger.stepSuccess(2, 'Server successfully started in Docker container'); - - logger.step(3, 'Launching dashboard stop action'); - await dashboard.runAction(constants.MAVEN_PROJECT, constants.STOP_DASHBOARD_ACTION, constants.STOP_DASHBOARD_MAC_ACTION); - - logger.step(4, 'Waiting for server to stop'); - const serverStopStatus = await utils.waitForServerStop(constants.SERVER_STOP_STRING); - - if (!serverStopStatus) { - logger.error('Server stopped message not found in the terminal'); - } else { - logger.stepSuccess(4, 'Server stopped successfully'); - } - expect(serverStopStatus).to.be.true; - } - - expect(serverStartStatus).to.be.true; - logger.testComplete('Start Maven with Docker from Liberty Tools'); - } catch (error) { - logger.testFailed('Start Maven with Docker from Liberty Tools', error); - throw error; - } - }).timeout(350000); - - it('Run tests for Maven project', async () => { - logger.testStart('Run tests for Maven project'); - try { - logger.step(1, 'Launching dashboard start action'); - await dashboard.runAction(constants.MAVEN_PROJECT, constants.START_DASHBOARD_ACTION, constants.START_DASHBOARD_MAC_ACTION); - - logger.step(2, 'Waiting for server to start'); - const serverStartStatus = await utils.waitForServerStart(constants.SERVER_START_STRING); - - if (!serverStartStatus) { - logger.error('Server started message not found in the terminal'); - } else { - logger.stepSuccess(2, 'Server successfully started'); - - logger.step(3, 'Launching run tests dashboard action'); - await dashboard.runAction(constants.MAVEN_PROJECT, constants.RUNTEST_DASHBOARD_ACTION, constants.RUNTEST_DASHBOARD_MAC_ACTION); - - logger.step(4, 'Checking test execution status'); - const testStatus = await utils.checkTestStatus(constants.MAVEN_RUN_TESTS_STRING); - logger.info(`Test status result: ${testStatus}`); - expect(testStatus).to.be.true; - logger.stepSuccess(4, 'Tests executed successfully'); - - logger.step(5, 'Launching dashboard stop action'); - await dashboard.runAction(constants.MAVEN_PROJECT, constants.STOP_DASHBOARD_ACTION, constants.STOP_DASHBOARD_MAC_ACTION); - - logger.step(6, 'Waiting for server to stop'); - const serverStopStatus = await utils.waitForServerStop(constants.SERVER_STOP_STRING); - - if (!serverStopStatus) { - logger.error('Server stopped message not found in the terminal'); - } else { - logger.stepSuccess(6, 'Server stopped successfully'); - } - expect(serverStopStatus).to.be.true; - } - - expect(serverStartStatus).to.be.true; - logger.testComplete('Run tests for Maven project'); - } catch (error) { - logger.testFailed('Run tests for Maven project', error); - throw error; - } - }).timeout(350000); - it('Start Maven with options from Liberty Tools', async () => { logger.testStart('Start Maven with options from Liberty Tools'); try { @@ -385,79 +195,6 @@ describe('Devmode action tests for Maven Project', () => { throw error; } }).timeout(90000); - - /** - * All future test cases should be written before the test that attaches the debugger, as this will switch the UI to the debugger view. - * If, for any reason, a test case needs to be written after the debugger test, ensure that the UI is switched back to the explorer view before executing the subsequent tests. - */ - it('Attach debugger for start with custom parameter event', async () => { - logger.testStart('Attach debugger for start with custom parameter event'); - let isServerRunning: Boolean = true; - let attachStatus: Boolean = false; - - try { - logger.step(1, 'Launching dashboard start action with custom parameters'); - await dashboard.runAction(constants.MAVEN_PROJECT, constants.START_DASHBOARD_ACTION_WITH_PARAM, constants.START_DASHBOARD_MAC_ACTION_WITH_PARAM); - - logger.step(2, 'Setting custom debug parameter: -DdebugPort=7777'); - await utils.setCustomParameter("-DdebugPort=7777"); - - logger.step(3, 'Waiting for server to start in debug mode'); - isServerRunning = await utils.waitForServerStart(constants.SERVER_START_STRING); - - if (!isServerRunning) { - logger.error('Server started with params message not found in terminal'); - } else { - logger.stepSuccess(3, 'Server successfully started in debug mode'); - - logger.step(4, 'Launching attach debugger dashboard action'); - await dashboard.runAction(constants.MAVEN_PROJECT, constants.ATTACH_DEBUGGER_DASHBOARD_ACTION, constants.ATTACH_DEBUGGER_DASHBOARD_MAC_ACTION); - logger.info('Attach Debugger action completed'); - - logger.step(5, 'Waiting for debugger to attach'); - attachStatus = await utils.waitForDebuggerAttach(); - - if (!attachStatus) { - logger.error('DebugToolbar not found - debugger may not have attached'); - } else { - logger.stepSuccess(5, 'Debugger attached successfully'); - } - - logger.step(6, 'Stopping Liberty server'); - await utils.stopLibertyserver(constants.MAVEN_PROJECT); - - logger.step(7, 'Waiting for server to stop'); - isServerRunning = !await utils.waitForServerStop(constants.SERVER_STOP_STRING); - - if (!isServerRunning) { - logger.stepSuccess(7, 'Server stopped successfully'); - } else { - logger.error('Server stop message not found in terminal'); - } - } - } catch (e) { - logger.error('Exception occurred during attach debugger test', e); - throw e; - } finally { - logger.info(`Finally block - Server running status: ${isServerRunning}`); - if (isServerRunning) { - logger.info('Attempting to stop server in finally block'); - await utils.stopLibertyserver(constants.MAVEN_PROJECT); - } else { - logger.info('Server already stopped, test cleanup complete'); - } - } - - expect(attachStatus).to.be.true; - logger.testComplete('Attach debugger for start with custom parameter event'); - }).timeout(350000); - - /** - * The following after hook copies the screenshot from the temporary folder in which it is saved to a known permanent location in the project folder. - */ - after(() => { - utils.copyScreenshotsToProjectFolder('maven'); - }); }); - +// Made with Bob diff --git a/src/test/MavenTestLSPHover.ts b/src/test/MavenTestLSPHover.ts index 2abef330..8c1ccd3b 100644 --- a/src/test/MavenTestLSPHover.ts +++ b/src/test/MavenTestLSPHover.ts @@ -1,188 +1,15 @@ -/* - * IBM Confidential - * Copyright IBM Corp. 2026 - */ -import { expect } from 'chai'; -import { EditorView, VSBrowser } from 'vscode-extension-tester'; import * as utils from './utils/testUtils'; -import { logger } from './utils/testLogger'; -import * as path from 'path'; -import { EditorPage } from './pages/EditorPage'; -import * as editorUtils from './utils/editorUtils'; +import { runHoverTestSuite } from './shared/hoverTestSuite'; -describe('LSP Hover tests for Maven Project', () => { - let serverXml: EditorPage; - - before(async function() { - this.timeout(60000); - - logger.info('Setting up Maven LSP Hover tests'); - - // Wait for workbench to be ready - await VSBrowser.instance.openResources(utils.getMvnProjectPath()); - await VSBrowser.instance.waitForWorkbench(); - - // Open server.xml file once for all tests - logger.info('Opening server.xml file for all tests'); - const serverXmlPath = path.resolve( - utils.getMvnProjectPath(), - 'src', - 'main', - 'liberty', - 'config', - 'server.xml' - ); - logger.info(`Server.xml path: ${serverXmlPath}`); - - serverXml = await new EditorPage().openFile(serverXmlPath, 'server.xml'); - logger.info('Server.xml file opened and editor obtained'); - }); - - afterEach(async function() { - // Take screenshot on failure but don't close editor - if (this.currentTest?.state === 'failed') { - await VSBrowser.instance.driver.takeScreenshot(); - logger.error(`Test failed: ${this.currentTest.title}`); - } - }); - - after(async function() { - this.timeout(10000); // Increase timeout for cleanup operations - // Close editor after all tests complete - try { - await new EditorView().closeAllEditors(); - logger.info('Closed all editors after test suite'); - } catch (error) { - logger.error('Failed to close editors in after hook', error); - } - - utils.copyScreenshotsToProjectFolder('maven'); - }); - - it('Liberty Language Server should initialize', async function() { - this.timeout(60000); - logger.testStart('Liberty Language Server should initialize'); - - try { - await utils.waitForLanguageServerInit( - 'Language Support for Liberty', - 'Initialized Liberty Language server', - 60 - ); - logger.testComplete('Liberty Language Server initialized successfully'); - } catch (error) { - logger.testFailed('Liberty Language Server should initialize', error); - throw error; - } - }); - - // Test data for parameterized hover tests - const hoverTestCases = [ +runHoverTestSuite({ + buildTool: 'maven', + getProjectPath: utils.getMvnProjectPath, + hoverTestCases: [ { element: 'httpEndpoint element', line: 19, column: 10, expectedDoc: 'Configuration properties for an HTTP endpoint.' }, { element: 'feature element', line: 16, column: 16, expectedDoc: 'Specifies a feature to be used when the server runs.' }, { element: 'featureManager element', line: 15, column: 10, expectedDoc: 'Defines how the server loads features.' }, { element: 'webApplication element', line: 21, column: 10, expectedDoc: 'Defines the properties of a web application.' }, { element: 'jsp-2.3 feature value', line: 16, column: 22, expectedDoc: 'This feature enables support for Java Server Pages (JSPs) that are written to the JSP 2.3 specification.' }, { element: 'httpPort attribute', line: 19, column: 33, expectedDoc: 'The port used for client HTTP requests. Use -1 to disable this port.' } - ]; - - hoverTestCases.forEach(testCase => { - it(`Hover over ${testCase.element} shows Liberty Language Server documentation`, async function() { - this.timeout(30000); - logger.testStart(`Hover over ${testCase.element} shows Liberty Language Server documentation`); - - try { - const hoverText = await editorUtils.hoverOver(serverXml.getEditor(), testCase.line, testCase.column, testCase.element); - expect(hoverText).to.not.be.empty; - logger.stepSuccess(3, `Hover widget displayed with Liberty Language Server content for ${testCase.element}`); - - logger.step(4, 'Verifying hover contains expected documentation'); - expect(hoverText).to.include(testCase.expectedDoc); - logger.stepSuccess(4, `Hover text contains expected documentation: "${testCase.expectedDoc}"`); - - logger.testComplete(`Hover over ${testCase.element} shows Liberty Language Server documentation`); - } catch (error) { - logger.testFailed(`Hover over ${testCase.element} shows Liberty Language Server documentation`, error); - throw error; - } - }); - }); - - describe('LSP4Jakarta Hover tests in Java file', () => { - let javaFile: EditorPage; - - before(async function() { - this.timeout(60000); - logger.info('Opening HelloServlet.java file for LSP4Jakarta hover tests'); - - const javaFilePath = path.resolve( - utils.getMvnProjectPath(), - 'src', - 'main', - 'java', - 'test', - 'maven', - 'liberty', - 'web', - 'app', - 'HelloServlet.java' - ); - logger.info(`Java file path: ${javaFilePath}`); - javaFile = await new EditorPage().openFile(javaFilePath, 'HelloServlet.java') - - logger.info('HelloServlet.java file opened and editor obtained'); - }); - - it('LSP4Jakarta Language Server should initialize', async function() { - this.timeout(60000); - logger.testStart('LSP4Jakarta Language Server should initialize'); - - try { - await utils.waitForLanguageServerInit( - 'Language Support for Jakarta EE', - 'Initializing Jakarta EE server', - 60 - ); - logger.testComplete('LSP4Jakarta Language Server initialized successfully'); - } catch (error) { - logger.testFailed('LSP4Jakarta Language Server should initialize', error); - throw error; - } - }); - - // Test data for LSP4Jakarta hover tests - const jakartaHoverTestCases = [ - { element: '@WebServlet annotation', line: 23, column: 2, expectedDoc: 'Annotation used to declare a servlet.' }, - { element: 'HttpServlet class', line: 24, column: 35, expectedDoc: 'Provides an abstract class to be subclassed to create an HTTP servlet suitable for a Web site.' }, - { element: 'HttpServletRequest type', line: 30, column: 35, expectedDoc: 'Extends the javax.servlet.ServletRequest interface to provide request information for HTTP servlets.' }, - { element: 'HttpServletResponse type', line: 30, column: 70, expectedDoc: 'Extends the ServletResponse interface to provide HTTP-specific functionality in sending a response.' } - ]; - - jakartaHoverTestCases.forEach(testCase => { - it(`Hover over ${testCase.element} shows LSP4Jakarta documentation`, async function() { - this.timeout(30000); - logger.testStart(`Hover over ${testCase.element} shows LSP4Jakarta documentation`); - - try { - const hoverText = await editorUtils.hoverOver(javaFile.getEditor(), testCase.line, testCase.column, testCase.element); - - expect(hoverText).to.not.be.empty; - logger.stepSuccess(3, `Hover widget displayed with LSP4Jakarta content for ${testCase.element}`); - - logger.step(4, 'Verifying hover contains expected documentation'); - expect(hoverText).to.include(testCase.expectedDoc); - logger.stepSuccess(4, `Hover text contains expected documentation: "${testCase.expectedDoc}"`); - - logger.testComplete(`Hover over ${testCase.element} shows LSP4Jakarta documentation`); - } catch (error) { - logger.testFailed(`Hover over ${testCase.element} shows LSP4Jakarta documentation`, error); - throw error; - } - }); - }); - }); - + ] }); - - - diff --git a/src/test/MavenTestLSPRestSnippetAndDiagnostic.ts b/src/test/MavenTestLSPRestSnippetAndDiagnostic.ts index 2253f191..068a6b59 100644 --- a/src/test/MavenTestLSPRestSnippetAndDiagnostic.ts +++ b/src/test/MavenTestLSPRestSnippetAndDiagnostic.ts @@ -1,176 +1,4 @@ - -/* - * IBM Confidential - * Copyright IBM Corp. 2026 - */ -import { expect } from 'chai'; -import { EditorView, VSBrowser, WebDriver } from 'vscode-extension-tester'; import * as utils from './utils/testUtils'; -import { logger } from './utils/testLogger'; -import * as path from 'path'; -import { ProblemsPage } from './pages/ProblemsPage'; -import { EditorPage } from './pages/EditorPage'; -import { CodeAssistPage } from './pages/CodeAssistPage'; -import { QuickFixPage } from './pages/QuickFixPage'; -import * as editorUtils from './utils/editorUtils'; - -describe('Rest Class Snippet Test for Maven Project', () => { - let editorPage: EditorPage; - let wait: any; - let driver: WebDriver; - - const testRestPath = path.resolve( - utils.getMvnProjectPath(), - 'src', 'main', 'java', 'test', 'maven', 'liberty', 'web', 'app', - 'TestRest.java' - ); - - before(async function() { - this.timeout(60000); - logger.info('Setting up rest_class snippet test'); - - driver = VSBrowser.instance.driver; - wait = utils.getWaitHelper(); - // Open folder, wait for workbench - await VSBrowser.instance.openResources(utils.getMvnProjectPath()); - await VSBrowser.instance.waitForWorkbench(); - - // Open file and bind page object to editor - editorPage = await new EditorPage().openFile(testRestPath, 'TestRest.java'); - - }); - - afterEach(async function() { - // Take screenshot on failure but don't close editor - if (this.currentTest?.state === 'failed') { - const driver = VSBrowser.instance.driver; - const screenshot = await driver.takeScreenshot(); - logger.error(`Test failed: ${this.currentTest.title}`); - } - }); - - after(async function() { - this.timeout(15000); - try { - if (editorPage) { - // Select all text first, then clear - const currentText = await editorPage.getEditor().getText(); - try { - await editorPage.getEditor().selectText(currentText); - await wait.sleep(300); - } catch (selectError) { - // selectText may fail but setText still works - } - - await editorUtils.clearEditor(editorPage.getEditor()); - logger.info('Reset TestRest.java to empty after test'); - } - } catch (error) { - logger.error('Failed to reset TestRest.java', error); - } - - try { - await new EditorView().closeAllEditors(); - await wait.sleep(500); - logger.info('Closed all editors after test suite'); - } catch (error) { - logger.error('Failed to close editors in after hook', error); - } - - utils.copyScreenshotsToProjectFolder('maven'); - }); - - it('LSP4Jakarta Language Server should initialize', async function() { - this.timeout(60000); - logger.testStart('LSP4Jakarta Language Server should initialize'); - - try { - await utils.waitForLanguageServerInit( - 'Language Support for Jakarta EE', - 'Initializing Jakarta EE server', - 60 - ); - logger.testComplete('LSP4Jakarta Language Server initialized successfully'); - } catch (error) { - logger.testFailed('LSP4Jakarta Language Server should initialize', error); - throw error; - } - }); - - it('rest_class snippet populates correct REST class', async function () { - this.timeout(275000); - logger.testStart('rest_class snippet inserts correct REST class'); - - // at the top of the rest_class snippet test, before positioning the cursor - await editorUtils.clearEditor(editorPage.getEditor()); - await wait.sleep(1500); // let any auto-stub settle, then confirm - const check = await editorPage.getEditor().getText(); - logger.info('Buffer before snippet: ' + JSON.stringify(check)); - - try { - logger.step(1, 'Positioning cursor for snippet insertion'); - // Position cursor at end of file - await editorUtils.moveCursorToEnd(editorPage.getEditor()); - - // Type rest and trigger snippet insertion - logger.step(2, 'Opening content assist'); - const codeAssist = new CodeAssistPage(); - await codeAssist.insertSnippet(editorPage, 'rest', 'rest_class'); - logger.stepSuccess(2, 'Snippet inserted'); - await wait.sleep(1000); // Give time for snippet to fully expand - - logger.step(3, 'Verifying snippet insertion'); - const codeInsertion = await editorPage.getEditor().getText(); - expect(codeInsertion).to.include('@GET') - expect(codeInsertion).to.include('methodname'); - logger.stepSuccess(3, 'Snippet rest_class was inserted correctly'); - - // Save the file so the content persists for the next test - await editorPage.getEditor().save(); - await wait.sleep(500); - - logger.testComplete('rest_class snippet inserts correct REST class'); - } catch (error) { - logger.testFailed('rest_class snippet inserts correct REST class', error); - throw error; - } - }); - it('Show that private @GET method displays diagnostic and quick fix removes it ', async function () { - this.timeout(90000); - logger.testStart('Diagnostic for a private @GET method and quick fix clears it'); - try { - // Find the method with @GET and change it to private - await editorUtils.replaceTextWithinLineContaining(editorPage.getEditor(), 'methodname', 'public', 'private'); - - // Save file and wait for reanalysis - await editorPage.getEditor().save(); - await wait.sleep(500); - - // Check that the diagnostic is there - let problems = new ProblemsPage(); - const found = await problems.hasDiagnostic('Only public methods can be exposed as resource methods.'); - expect(found).to.be.true; - logger.testComplete('Diagnostic shows for private @GET method'); - - // Quick fix implementation to get rid of diagnostic - // Re-find line and place cursor on "methodname()" - const buffer = await editorPage.getEditor().getText(); - logger.info('Buffer before quick fix: ' + JSON.stringify(buffer)); - - await new QuickFixPage().applyFix(editorPage, 'methodname', 'make method public'); - await wait.sleep(3000); - await editorPage.getEditor().save(); - await wait.sleep(5000); - - const after = await editorPage.getEditor().getText(); - expect(after).to.include('public String methodname'); - expect(await problems.hasDiagnostic('Only public methods can be exposed as resource methods.')).to.be.false; - - } catch (error) { - logger.testFailed('Diagnostic/quick-fix test flow failed', error); - throw error; - } - - }); - }); +import { runRestSnippetSuite } from './shared/restSnippetSuite'; +runRestSnippetSuite({ buildTool: 'maven', getProjectPath: utils.getMvnProjectPath }); \ No newline at end of file diff --git a/src/test/shared/devModeTestSuite.ts b/src/test/shared/devModeTestSuite.ts new file mode 100644 index 00000000..749fcc0f --- /dev/null +++ b/src/test/shared/devModeTestSuite.ts @@ -0,0 +1,298 @@ +import { expect } from 'chai'; +import { DefaultTreeItem, EditorView, SideBarView, ViewItem, ViewSection, VSBrowser, Workbench, WebDriver } from 'vscode-extension-tester'; +import * as utils from '../utils/testUtils'; +import * as constants from '../definitions/constants'; +import { logger } from '../utils/testLogger'; +import path = require('path'); +import { DashboardPage } from '../pages/DashboardPage'; + +export interface DevModeConfig { + buildTool: 'maven' | 'gradle'; + getProjectPath: () => string; + projectConstant: string; + testRunString: string; +} + +export function runDevModeTestSuite(config: DevModeConfig): void { + let dashboard!: DashboardPage; + + describe(`Devmode action tests for ${config.buildTool} Project`, () => { + + before(async function() { + this.timeout(30000); + + await VSBrowser.instance.openResources(config.getProjectPath()); + await VSBrowser.instance.waitForWorkbench(); + + dashboard = new DashboardPage(); + }); + + afterEach(async function() { + this.timeout(10000); // Increase timeout for cleanup operations + // Close any open editors after each test + if (this.currentTest?.state === 'failed') { + await VSBrowser.instance.driver.takeScreenshot(); + logger.error(`Test failed: ${this.currentTest.title}`); + } + + try { + await new EditorView().closeAllEditors(); + } catch (error) { + logger.error('Failed to close editors in afterEach', error); + } + + // Clear terminal between tests to avoid confusion with old output + try { + const workbench = new Workbench(); + await workbench.executeCommand('terminal clear'); + } catch (error) { + logger.error('Failed to clear terminal in afterEach', error); + } + }); + it('Find Liberty Tools in sidebar', async () => { + logger.testStart('Find Liberty Tools in sidebar'); + try { + logger.step(1, 'Attempting to get Liberty Tools section'); + const section = await dashboard.getSection(); + logger.stepSuccess(1, 'Found Liberty Tools section'); + + logger.step(2, 'Validating sidebar is not undefined'); + expect(section).not.undefined; + logger.testComplete('Find Liberty Tools in sidebar'); + } catch (error) { + logger.testFailed('Find Liberty Tools in sidebar', error); + throw error; + } + }).timeout(60000); + it(`Liberty Tools shows items - ${config.buildTool}`, async () => { + logger.testStart('Liberty Tools shows items - Maven'); + try { + logger.step(1, 'Getting dashboard section'); + const section = await dashboard.getSection(); + logger.stepSuccess(1, 'Dashboard section retrieved'); + + logger.step(2, 'Waiting for Liberty Tools to load'); + await utils.waitForDashboardToLoad(section); + logger.stepSuccess(2, 'Liberty Tools loaded successfully'); + + logger.step(3, 'Getting visible items from section'); + const menu = await utils.waitForCondition(async () => { + const items = await section.getVisibleItems(); + if (items && items.length > 0) { + return items; + } + return; + }, 60); + logger.info(`Found ${menu.length} visible items in dashboard`); + expect(menu).not.empty; + + logger.step(4, `Finding Maven project item: ${config.projectConstant}`); + const item = await dashboard.getProjectItem(config.projectConstant); + logger.stepSuccess(4, 'Maven project item found'); + expect(item).not.undefined; + + logger.testComplete(`Liberty Tools shows items - ${config.buildTool}`); + } catch (error) { + logger.testFailed(`Liberty Tools shows items - ${config.buildTool}`, error); + throw error; + } + }).timeout(275000); + + it(`Start ${config.buildTool} project from Liberty Tools`, async () => { + logger.testStart('Start Maven project from Liberty Tools'); + try { + logger.step(1, 'Getting dashboard section and item'); + await dashboard.runAction(config.projectConstant, constants.START_DASHBOARD_ACTION, constants.START_DASHBOARD_MAC_ACTION); + + logger.step(2, 'Waiting for server to start'); + const serverStartStatus = await utils.waitForServerStart(constants.SERVER_START_STRING); + + if (!serverStartStatus) { + logger.error('Server started message not found in the terminal'); + } else { + logger.stepSuccess(2, 'Server successfully started'); + + logger.step(3, 'Launching dashboard stop action'); + await dashboard.runAction(config.projectConstant, constants.STOP_DASHBOARD_ACTION, constants.STOP_DASHBOARD_MAC_ACTION); + + logger.step(4, 'Waiting for server to stop'); + const serverStopStatus = await utils.waitForServerStop(constants.SERVER_STOP_STRING); + + if (!serverStopStatus) { + logger.error('Server stopped message not found in the terminal'); + } else { + logger.stepSuccess(4, 'Server stopped successfully'); + } + expect(serverStopStatus).to.be.true; + } + + expect(serverStartStatus).to.be.true; + logger.testComplete(`Start ${config.buildTool} project from Liberty Tools`); + } catch (error) { + logger.testFailed(`Start ${config.buildTool} project from Liberty Tools`, error); + throw error; + } + }).timeout(550000); + + it(`Start ${config.buildTool} with Docker from Liberty Tools`, async () => { + logger.testStart('Start Maven with Docker from Liberty Tools'); + + if ((process.platform === 'darwin') || (process.platform === 'win32')) { + logger.skip(`Test skipped for platform: ${process.platform} (Docker test only runs on Linux)`); + return true; + } + + try { + logger.step(1, 'Launching dashboard start action with Docker'); + await dashboard.runAction(config.projectConstant, constants.START_DASHBOARD_ACTION_WITHDOCKER, constants.START_DASHBOARD_MAC_ACTION_WITHDOCKER); + + logger.step(2, 'Waiting for server to start in Docker container'); + const serverStartStatus = await utils.waitForServerStart(constants.SERVER_START_STRING); + + if (!serverStartStatus) { + logger.error('Server started message not found in the terminal'); + } else { + logger.stepSuccess(2, 'Server successfully started in Docker container'); + + logger.step(3, 'Launching dashboard stop action'); + await dashboard.runAction(config.projectConstant, constants.STOP_DASHBOARD_ACTION, constants.STOP_DASHBOARD_MAC_ACTION); + + logger.step(4, 'Waiting for server to stop'); + const serverStopStatus = await utils.waitForServerStop(constants.SERVER_STOP_STRING); + + if (!serverStopStatus) { + logger.error('Server stopped message not found in the terminal'); + } else { + logger.stepSuccess(4, 'Server stopped successfully'); + } + expect(serverStopStatus).to.be.true; + } + + expect(serverStartStatus).to.be.true; + logger.testComplete(`Start ${config.buildTool} with Docker from Liberty Tools`); + } catch (error) { + logger.testFailed(`Start ${config.buildTool} with Docker from Liberty Tools`, error); + throw error; + } + }).timeout(350000); + + it(`Run tests for ${config.buildTool} project`, async () => { + logger.testStart('Run tests for Maven project'); + try { + logger.step(1, 'Launching dashboard start action'); + await dashboard.runAction(config.projectConstant, constants.START_DASHBOARD_ACTION, constants.START_DASHBOARD_MAC_ACTION); + + logger.step(2, 'Waiting for server to start'); + const serverStartStatus = await utils.waitForServerStart(constants.SERVER_START_STRING); + + if (!serverStartStatus) { + logger.error('Server started message not found in the terminal'); + } else { + logger.stepSuccess(2, 'Server successfully started'); + + logger.step(3, 'Launching run tests dashboard action'); + await dashboard.runAction(config.projectConstant, constants.RUNTEST_DASHBOARD_ACTION, constants.RUNTEST_DASHBOARD_MAC_ACTION); + + logger.step(4, 'Checking test execution status'); + const testStatus = await utils.checkTestStatus(config.testRunString); + logger.info(`Test status result: ${testStatus}`); + expect(testStatus).to.be.true; + logger.stepSuccess(4, 'Tests executed successfully'); + + logger.step(5, 'Launching dashboard stop action'); + await dashboard.runAction(config.projectConstant, constants.STOP_DASHBOARD_ACTION, constants.STOP_DASHBOARD_MAC_ACTION); + + logger.step(6, 'Waiting for server to stop'); + const serverStopStatus = await utils.waitForServerStop(constants.SERVER_STOP_STRING); + + if (!serverStopStatus) { + logger.error('Server stopped message not found in the terminal'); + } else { + logger.stepSuccess(6, 'Server stopped successfully'); + } + expect(serverStopStatus).to.be.true; + } + + expect(serverStartStatus).to.be.true; + logger.testComplete(`Run tests for ${config.buildTool} project`); + } catch (error) { + logger.testFailed(`Run tests for ${config.buildTool} project`, error); + throw error; + } + }).timeout(350000); + + /** + * All future test cases should be written before the test that attaches the debugger, as this will switch the UI to the debugger view. + * If, for any reason, a test case needs to be written after the debugger test, ensure that the UI is switched back to the explorer view before executing the subsequent tests. + */ + it(`Attach debugger for ${config.buildTool} with custom parameter event`, async () => { + logger.testStart('Attach debugger for start with custom parameter event'); + let isServerRunning: Boolean = true; + let attachStatus: Boolean = false; + + try { + logger.step(1, 'Launching dashboard start action with custom parameters'); + await dashboard.runAction(config.projectConstant, constants.START_DASHBOARD_ACTION_WITH_PARAM, constants.START_DASHBOARD_MAC_ACTION_WITH_PARAM); + + logger.step(2, 'Setting custom debug parameter: -DdebugPort=7777'); + await utils.setCustomParameter("-DdebugPort=7777"); + + logger.step(3, 'Waiting for server to start in debug mode'); + isServerRunning = await utils.waitForServerStart(constants.SERVER_START_STRING); + + if (!isServerRunning) { + logger.error('Server started with params message not found in terminal'); + } else { + logger.stepSuccess(3, 'Server successfully started in debug mode'); + + logger.step(4, 'Launching attach debugger dashboard action'); + await dashboard.runAction(config.projectConstant, constants.ATTACH_DEBUGGER_DASHBOARD_ACTION, constants.ATTACH_DEBUGGER_DASHBOARD_MAC_ACTION); + logger.info('Attach Debugger action completed'); + + logger.step(5, 'Waiting for debugger to attach'); + attachStatus = await utils.waitForDebuggerAttach(); + + if (!attachStatus) { + logger.error('DebugToolbar not found - debugger may not have attached'); + } else { + logger.stepSuccess(5, 'Debugger attached successfully'); + } + + logger.step(6, 'Stopping Liberty server'); + await utils.stopLibertyserver(config.projectConstant); + + logger.step(7, 'Waiting for server to stop'); + isServerRunning = !await utils.waitForServerStop(constants.SERVER_STOP_STRING); + + if (!isServerRunning) { + logger.stepSuccess(7, 'Server stopped successfully'); + } else { + logger.error('Server stop message not found in terminal'); + } + } + } catch (e) { + logger.error('Exception occurred during attach debugger test', e); + throw e; + } finally { + logger.info(`Finally block - Server running status: ${isServerRunning}`); + if (isServerRunning) { + logger.info('Attempting to stop server in finally block'); + await utils.stopLibertyserver(config.projectConstant); + } else { + logger.info('Server already stopped, test cleanup complete'); + } + } + + expect(attachStatus).to.be.true; + logger.testComplete(`Attach debugger for ${config.buildTool} with custom parameter event`); + }).timeout(350000); + + /** + * The following after hook copies the screenshot from the temporary folder in which it is saved to a known permanent location in the project folder. + */ + after(() => { + utils.copyScreenshotsToProjectFolder(config.buildTool); + }); + + }); +} \ No newline at end of file diff --git a/src/test/shared/hoverTestSuite.ts b/src/test/shared/hoverTestSuite.ts new file mode 100644 index 00000000..dbe700a5 --- /dev/null +++ b/src/test/shared/hoverTestSuite.ts @@ -0,0 +1,194 @@ +/* + * IBM Confidential + * Copyright IBM Corp. 2026 + */ +import { expect } from 'chai'; +import { EditorView, TextEditor, VSBrowser, Workbench, WebDriver } from 'vscode-extension-tester'; +import * as utils from '../utils/testUtils'; +import { logger } from '../utils/testLogger'; +import * as path from 'path'; +import * as editorUtils from '../utils/editorUtils'; +import { EditorPage } from '../pages/EditorPage'; + +export interface HoverConfig { + buildTool: 'maven' | 'gradle'; + getProjectPath: () => string; + hoverTestCases: Array<{ + element: string; + line: number; + column: number; + expectedDoc: string; + }>; +} + +export function runHoverTestSuite(config: HoverConfig){ + describe(`LSP Hover tests for ${config.buildTool === 'maven' ? 'Maven' : 'Gradle'} Project`, () => { + let serverXml: EditorPage; + + before(async function() { + this.timeout(60000); + + logger.info(`Setting up ${config.buildTool === 'maven' ? 'Maven' : 'Gradle'} LSP Hover tests`); + + // Wait for workbench to be ready + await VSBrowser.instance.openResources(config.getProjectPath()); + await VSBrowser.instance.waitForWorkbench(); + + // Open server.xml file once for all tests + logger.info('Opening server.xml file for all tests'); + const serverXmlPath = path.resolve( + config.getProjectPath(), + 'src', + 'main', + 'liberty', + 'config', + 'server.xml' + ); + logger.info(`Server.xml path: ${serverXmlPath}`); + + serverXml = await new EditorPage().openFile(serverXmlPath, 'server.xml'); + logger.info('Server.xml file opened and editor obtained'); + }); + + afterEach(async function() { + // Take screenshot on failure but don't close editor + if (this.currentTest?.state === 'failed') { + await VSBrowser.instance.driver.takeScreenshot(); + logger.error(`Test failed: ${this.currentTest.title}`); + } + }); + + after(async function() { + this.timeout(10000); // Increase timeout for cleanup operations + // Close editor after all tests complete + try { + await new EditorView().closeAllEditors(); + logger.info('Closed all editors after test suite'); + } catch (error) { + logger.error('Failed to close editors in after hook', error); + } + + utils.copyScreenshotsToProjectFolder(config.buildTool); + }); + + it('Liberty Language Server should initialize', async function() { + this.timeout(60000); + logger.testStart('Liberty Language Server should initialize'); + + try { + await utils.waitForLanguageServerInit( + 'Language Support for Liberty', + 'Initialized Liberty Language server', + 60 + ); + logger.testComplete('Liberty Language Server initialized successfully'); + } catch (error) { + logger.testFailed('Liberty Language Server should initialize', error); + throw error; + } + }); + + // Test data for parameterized hover tests + const hoverTestCases = config.hoverTestCases; + + hoverTestCases.forEach(testCase => { + it(`Hover over ${testCase.element} shows Liberty Language Server documentation`, async function() { + this.timeout(30000); + logger.testStart(`Hover over ${testCase.element} shows Liberty Language Server documentation`); + + try { + const hoverText = await editorUtils.hoverOver(serverXml.getEditor(), testCase.line, testCase.column, testCase.element); + expect(hoverText).to.not.be.empty; + logger.stepSuccess(3, `Hover widget displayed with Liberty Language Server content for ${testCase.element}`); + + logger.step(4, 'Verifying hover contains expected documentation'); + expect(hoverText).to.include(testCase.expectedDoc); + logger.stepSuccess(4, `Hover text contains expected documentation: "${testCase.expectedDoc}"`); + + logger.testComplete(`Hover over ${testCase.element} shows Liberty Language Server documentation`); + } catch (error) { + logger.testFailed(`Hover over ${testCase.element} shows Liberty Language Server documentation`, error); + throw error; + } + }); + }); + + describe('LSP4Jakarta Hover tests in Java file', () => { + let javaFile: EditorPage; + + before(async function() { + this.timeout(60000); + logger.info('Opening HelloServlet.java file for LSP4Jakarta hover tests'); + + const javaFilePath = path.resolve( + config.getProjectPath(), + 'src', + 'main', + 'java', + 'test', + config.buildTool, + 'liberty', + 'web', + 'app', + 'HelloServlet.java' + ); + logger.info(`Java file path: ${javaFilePath}`); + javaFile = await new EditorPage().openFile(javaFilePath, 'HelloServlet.java'); + + logger.info('HelloServlet.java file opened and editor obtained'); + }); + + it('LSP4Jakarta Language Server should initialize', async function() { + this.timeout(60000); + logger.testStart('LSP4Jakarta Language Server should initialize'); + + try { + await utils.waitForLanguageServerInit( + 'Language Support for Jakarta EE', + 'Initializing Jakarta EE server', + 60 + ); + logger.testComplete('LSP4Jakarta Language Server initialized successfully'); + } catch (error) { + logger.testFailed('LSP4Jakarta Language Server should initialize', error); + throw error; + } + }); + + // Test data for LSP4Jakarta hover tests + const jakartaHoverTestCases = [ + { element: '@WebServlet annotation', line: 23, column: 2, expectedDoc: 'Annotation used to declare a servlet.' }, + { element: 'HttpServlet class', line: 24, column: 35, expectedDoc: 'Provides an abstract class to be subclassed to create an HTTP servlet suitable for a Web site.' }, + { element: 'HttpServletRequest type', line: 30, column: 35, expectedDoc: 'Extends the javax.servlet.ServletRequest interface to provide request information for HTTP servlets.' }, + { element: 'HttpServletResponse type', line: 30, column: 70, expectedDoc: 'Extends the ServletResponse interface to provide HTTP-specific functionality in sending a response.' } + ]; + + jakartaHoverTestCases.forEach(testCase => { + it(`Hover over ${testCase.element} shows LSP4Jakarta documentation`, async function() { + this.timeout(30000); + logger.testStart(`Hover over ${testCase.element} shows LSP4Jakarta documentation`); + + try { + const hoverText = await editorUtils.hoverOver(javaFile.getEditor(), testCase.line, testCase.column, testCase.element); + + expect(hoverText).to.not.be.empty; + logger.stepSuccess(3, `Hover widget displayed with LSP4Jakarta content for ${testCase.element}`); + + logger.step(4, 'Verifying hover contains expected documentation'); + expect(hoverText).to.include(testCase.expectedDoc); + logger.stepSuccess(4, `Hover text contains expected documentation: "${testCase.expectedDoc}"`); + + logger.testComplete(`Hover over ${testCase.element} shows LSP4Jakarta documentation`); + } catch (error) { + logger.testFailed(`Hover over ${testCase.element} shows LSP4Jakarta documentation`, error); + throw error; + } + }); + }); + }); + + }); +} + + + diff --git a/src/test/shared/restSnippetSuite.ts b/src/test/shared/restSnippetSuite.ts new file mode 100644 index 00000000..36550f1b --- /dev/null +++ b/src/test/shared/restSnippetSuite.ts @@ -0,0 +1,185 @@ +/* + * IBM Confidential + * Copyright IBM Corp. 2026 + */ +import { expect } from 'chai'; +import { EditorView, TextEditor, VSBrowser, Workbench, WebDriver, BottomBarPanel, MarkerType, Key, By } from 'vscode-extension-tester'; +import * as utils from '../utils/testUtils'; +import { logger } from '../utils/testLogger'; +import * as path from 'path'; +import { ProblemsPage } from '../pages/ProblemsPage'; +import { EditorPage } from '../pages/EditorPage'; +import { CodeAssistPage } from '../pages/CodeAssistPage'; +import { QuickFixPage } from '../pages/QuickFixPage'; +import * as editorUtils from '../utils/editorUtils'; + +// Configuration interface for parameterizing the test suite +export interface RestSnippetConfig { + buildTool: 'maven' | 'gradle'; + getProjectPath: () => string; +} + +// Shared test suite that works for both Maven and Gradle +export function runRestSnippetSuite(config: RestSnippetConfig) { + describe(`Rest Class Snippet Test for ${config.buildTool === 'maven' ? 'Maven' : 'Gradle'} Project`, () => { + let editorPage: EditorPage; + let wait: any; + let driver: WebDriver; + + // Compute the test file path using config + const testRestPath = path.resolve( + config.getProjectPath(), + 'src', 'main', 'java', 'test', config.buildTool, 'liberty', 'web', 'app', + 'TestRest.java' + ); + + before(async function() { + this.timeout(60000); + logger.info('Setting up rest_class snippet test'); + + driver = VSBrowser.instance.driver; + wait = utils.getWaitHelper(); + // Open folder, wait for workbench + await VSBrowser.instance.openResources(config.getProjectPath()); + await VSBrowser.instance.waitForWorkbench(); + + // Open file and bind page object to editor + editorPage = await new EditorPage().openFile(testRestPath, 'TestRest.java'); + + }); + + afterEach(async function() { + // Take screenshot on failure but don't close editor + if (this.currentTest?.state === 'failed') { + const driver = VSBrowser.instance.driver; + const screenshot = await driver.takeScreenshot(); + logger.error(`Test failed: ${this.currentTest.title}`); + } + }); + + after(async function() { + this.timeout(15000); + try { + if (editorPage) { + // Select all text first, then clear + const currentText = await editorPage.getEditor().getText(); + try { + await editorPage.getEditor().selectText(currentText); + await wait.sleep(300); + } catch (selectError) { + // selectText may fail but setText still works + } + + await editorUtils.clearEditor(editorPage.getEditor()) + logger.info('Reset TestRest.java to empty after test'); + } + } catch (error) { + logger.error('Failed to reset TestRest.java', error); + } + + try { + await new EditorView().closeAllEditors(); + await wait.sleep(500); + logger.info('Closed all editors after test suite'); + } catch (error) { + logger.error('Failed to close editors in after hook', error); + } + + utils.copyScreenshotsToProjectFolder(config.buildTool); + }); + + it('LSP4Jakarta Language Server should initialize', async function() { + this.timeout(60000); + logger.testStart('LSP4Jakarta Language Server should initialize'); + + try { + await utils.waitForLanguageServerInit( + 'Language Support for Jakarta EE', + 'Initializing Jakarta EE server', + 60 + ); + logger.testComplete('LSP4Jakarta Language Server initialized successfully'); + } catch (error) { + logger.testFailed('LSP4Jakarta Language Server should initialize', error); + throw error; + } + }); + + it('rest_class snippet populates correct REST class', async function () { + this.timeout(275000); + logger.testStart('rest_class snippet inserts correct REST class'); + + // at the top of the rest_class snippet test, before positioning the cursor + await editorUtils.clearEditor(editorPage.getEditor()); + await wait.sleep(1500); // let any auto-stub settle, then confirm + const check = await editorPage.getEditor().getText(); + logger.info('Buffer before snippet: ' + JSON.stringify(check)); + + try { + logger.step(1, 'Positioning cursor for snippet insertion'); + // Position cursor at end of file + await editorUtils.moveCursorToEnd(editorPage.getEditor()); + + // Type rest and trigger snippet insertion + logger.step(2, 'Opening content assist'); + const codeAssist = new CodeAssistPage(); + await codeAssist.insertSnippet(editorPage, 'rest', 'rest_class'); + logger.stepSuccess(2, 'Snippet inserted'); + await wait.sleep(1000); // Give time for snippet to fully expand + + logger.step(3, 'Verifying snippet insertion'); + const codeInsertion = await editorPage.getEditor().getText(); + expect(codeInsertion).to.include('@GET') + expect(codeInsertion).to.include('methodname'); + logger.stepSuccess(3, 'Snippet rest_class was inserted correctly'); + + // Save the file so the content persists for the next test + await editorPage.getEditor().save(); + await wait.sleep(500); + + logger.testComplete('rest_class snippet inserts correct REST class'); + } catch (error) { + logger.testFailed('rest_class snippet inserts correct REST class', error); + throw error; + } + }); + it('Show that private @GET method displays diagnostic and quick fix removes it ', async function () { + this.timeout(90000); + logger.testStart('Diagnostic for a private @GET method and quick fix clears it'); + try { + // Find the method with @GET and change it to private + await editorUtils.replaceTextWithinLineContaining(editorPage.getEditor(), 'methodname', 'public', 'private'); + + // Save file and wait for reanalysis + await editorPage.getEditor().save(); + await wait.sleep(500); + + // Check that the diagnostic is there + let problems = new ProblemsPage(); + const found = await problems.hasDiagnostic('Only public methods can be exposed as resource methods.'); + expect(found).to.be.true; + logger.testComplete('Diagnostic shows for private @GET method'); + + // Quick fix implementation to get rid of diagnostic + // Re-find line and place cursor on "methodname()" + const buffer = await editorPage.getEditor().getText(); + logger.info('Buffer before quick fix: ' + JSON.stringify(buffer)); + + await new QuickFixPage().applyFix(editorPage, 'methodname', 'make method public'); + await wait.sleep(3000); + await editorPage.getEditor().save(); + await wait.sleep(5000); + + const after = await editorPage.getEditor().getText(); + expect(after).to.include('public String methodname'); + expect(await problems.hasDiagnostic('Only public methods can be exposed as resource methods.')).to.be.false; + + } catch (error) { + logger.testFailed('Diagnostic/quick-fix test flow failed', error); + throw error; + } + + }); + }); +} + From 1b236986e66af253546a9bf1c9f7bcc3c1b6ece3 Mon Sep 17 00:00:00 2001 From: Venya Sharma Date: Fri, 26 Jun 2026 13:32:24 -0500 Subject: [PATCH 2/4] fixes to allow shared suite builds to only run into rest-snippet error due to LSP4Jakarta issues --- src/test/MavenTestDevModeActions.ts | 9 +++++++++ src/test/pages/EditorPage.ts | 10 +++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/test/MavenTestDevModeActions.ts b/src/test/MavenTestDevModeActions.ts index 124ab96d..7d963b27 100755 --- a/src/test/MavenTestDevModeActions.ts +++ b/src/test/MavenTestDevModeActions.ts @@ -28,6 +28,15 @@ describe('Maven-specific devmode action tests', () => { dashboard = new DashboardPage(); }); + after(async function() { + this.timeout(10000); + try { + await new EditorView().closeAllEditors(); + } catch (error) { + logger.error('Failed to close editors after Maven-specific suite', error); + } + }); + it('Start Maven with options from Liberty Tools', async () => { logger.testStart('Start Maven with options from Liberty Tools'); try { diff --git a/src/test/pages/EditorPage.ts b/src/test/pages/EditorPage.ts index 1f580d0d..4c116769 100644 --- a/src/test/pages/EditorPage.ts +++ b/src/test/pages/EditorPage.ts @@ -6,9 +6,9 @@ import { EditorView, TextEditor, VSBrowser } from 'vscode-extension-tester'; import * as utils from '../utils/testUtils'; -export class EditorPage { - private editor!: TextEditor; - private editorView = new EditorView(); +export class EditorPage { + private editor!: TextEditor; + private editorView = new EditorView(); /** * Open a file and bind this page object to its editor. @@ -18,10 +18,10 @@ export class EditorPage { */ async openFile(filePath: string, tabTitle: string, loadDelay = 3000): Promise { await VSBrowser.instance.openResources(filePath, async () => { - await utils.getWaitHelper().sleep(loadDelay); + await utils.getWaitHelper().sleep(loadDelay); }); this.editor = await this.editorView.openEditor(tabTitle) as TextEditor; - return this; + return this; } getEditor(): TextEditor { From 58d3563ffe3e69590770ae7677ffaa8ac050d86a Mon Sep 17 00:00:00 2001 From: Venya Sharma Date: Fri, 26 Jun 2026 16:26:28 -0500 Subject: [PATCH 3/4] Refactor Gradle9TestDevModeActions to use shared devModeTestSuite --- src/test/Gradle9TestDevModeActions.ts | 291 ++------------------------ 1 file changed, 13 insertions(+), 278 deletions(-) diff --git a/src/test/Gradle9TestDevModeActions.ts b/src/test/Gradle9TestDevModeActions.ts index fd8e166a..32b5e247 100644 --- a/src/test/Gradle9TestDevModeActions.ts +++ b/src/test/Gradle9TestDevModeActions.ts @@ -1,230 +1,32 @@ -// test same functionality as GradleTestDevModeActions -// make sure paths or constants that call liberty-gradle-test-wrapper call liberty-gradle-9-test-wrapper here -// make sure you can run it as an individual test - /* * IBM Confidential * Copyright IBM Corp. 2023, 2026 */ import { expect } from 'chai'; -import { EditorView, VSBrowser, Workbench } from 'vscode-extension-tester'; +import { runDevModeTestSuite } from "./shared/devModeTestSuite"; import * as utils from './utils/testUtils'; import * as constants from './definitions/constants'; import { logger } from './utils/testLogger'; import path = require('path'); import { DashboardPage } from './pages/DashboardPage'; -describe('Open and conduct devmode action tests for Gradle 9.0 Project', () => { +// Run shared dev mode tests with Gradle 9 configuration +runDevModeTestSuite({ + buildTool: 'gradle', + getProjectPath: utils.getGradle9ProjectPath, + projectConstant: constants.GRADLE_9_PROJECT, + testRunString: constants.GRADLE_TEST_RUN_STRING +}); + +// Gradle 9-specific tests in their own describe block +describe('Gradle 9-specific devmode action tests', () => { let dashboard: DashboardPage; before(async function() { this.timeout(30000); - - await VSBrowser.instance.openResources(utils.getGradle9ProjectPath()); - await VSBrowser.instance.waitForWorkbench(); - dashboard = new DashboardPage(); }); - afterEach(async function() { - this.timeout(10000); // Increase timeout for cleanup operations - // Close any open editors after each test - if (this.currentTest?.state === 'failed') { - await VSBrowser.instance.driver.takeScreenshot(); - logger.error(`Test failed: ${this.currentTest.title}`); - } - - try { - await new EditorView().closeAllEditors(); - } catch (error) { - logger.error('Failed to close editors in afterEach', error); - } - - // Clear terminal between tests to avoid confusion with old output - try { - const workbench = new Workbench(); - await workbench.executeCommand('terminal clear'); - } catch (error) { - logger.error('Failed to clear terminal in afterEach', error); - } - }); - - - it('Find Liberty Tools in sidebar', async () => { - logger.testStart('Find Liberty Tools in sidebar'); - try { - logger.step(1, 'Attempting to get Liberty Tools section'); - const section = await dashboard.getSection(); - logger.stepSuccess(1, 'Found Liberty Tools section'); - - logger.step(2, 'Validating sidebar is not undefined'); - expect(section).not.undefined; - logger.testComplete('Find Liberty Tools in sidebar'); - } catch (error) { - logger.testFailed('Find Liberty Tools in sidebar', error); - throw error; - } - }).timeout(60000); - - it('Liberty Tools shows items - Gradle', async () => { - logger.testStart('Liberty Tools shows items - Gradle'); - try { - logger.step(1, 'Getting dashboard section'); - const section = await dashboard.getSection(); - logger.stepSuccess(1, 'Dashboard section retrieved'); - - logger.step(2, 'Waiting for Liberty Tools to load'); - await utils.waitForDashboardToLoad(section); - logger.stepSuccess(2, 'Liberty Tools loaded successfully'); - - logger.step(3, 'Getting visible items from section'); - const menu = await utils.waitForCondition(async () => { - const items = await section.getVisibleItems(); - if (items && items.length > 0) { - return items; - } - return; - }, 60); - logger.info(`Found ${menu.length} visible items in dashboard`); - expect(menu).not.empty; - - logger.step(4, `Finding Gradle project item: ${constants.GRADLE_9_PROJECT}`); - const item = await dashboard.getProjectItem(constants.GRADLE_9_PROJECT); - logger.stepSuccess(4, 'Gradle project item found'); - expect(item).not.undefined; - - logger.testComplete('Liberty Tools shows items - Gradle'); - } catch (error) { - logger.testFailed('Liberty Tools shows items - Gradle', error); - throw error; - } - }).timeout(300000); - - it('Start Gradle project from Liberty Tools', async () => { - logger.testStart('Start Gradle project from Liberty Tools'); - try { - logger.step(1, 'Launching dashboard start action'); - await dashboard.runAction(constants.GRADLE_9_PROJECT, constants.START_DASHBOARD_ACTION, constants.START_DASHBOARD_MAC_ACTION); - - logger.step(2, 'Waiting for server to start'); - const serverStartStatus = await utils.waitForServerStart(constants.SERVER_START_STRING); - - if (!serverStartStatus) { - logger.error('Server started message not found in the terminal'); - } else { - logger.stepSuccess(2, 'Server successfully started'); - - logger.step(3, 'Launching dashboard stop action'); - await dashboard.runAction(constants.GRADLE_9_PROJECT, constants.STOP_DASHBOARD_ACTION, constants.STOP_DASHBOARD_MAC_ACTION); - - logger.step(4, 'Waiting for server to stop'); - const serverStopStatus = await utils.waitForServerStop(constants.SERVER_STOP_STRING); - - if (!serverStopStatus) { - logger.error('Server stopped message not found in the terminal'); - } else { - logger.stepSuccess(4, 'Server stopped successfully'); - } - expect(serverStopStatus).to.be.true; - } - - expect(serverStartStatus).to.be.true; - logger.testComplete('Start Gradle project from Liberty Tools'); - } catch (error) { - logger.testFailed('Start Gradle project from Liberty Tools', error); - throw error; - } - }).timeout(350000); - - it('Start Gradle with Docker from Liberty Tools', async () => { - logger.testStart('Start Gradle with Docker from Liberty Tools'); - - if ((process.platform === 'darwin') || (process.platform === 'win32')) { - logger.skip(`Test skipped for platform: ${process.platform} (Docker test only runs on Linux)`); - return true; - } - - try { - logger.step(1, 'Launching dashboard start action with Docker'); - await dashboard.runAction(constants.GRADLE_9_PROJECT, constants.START_DASHBOARD_ACTION_WITHDOCKER, constants.START_DASHBOARD_MAC_ACTION_WITHDOCKER); - - logger.step(2, 'Waiting for server to start in Docker container'); - const serverStartStatus = await utils.waitForServerStart(constants.SERVER_START_STRING); - - if (!serverStartStatus) { - logger.error('Server started message not found in the terminal'); - } else { - logger.stepSuccess(2, 'Server successfully started in Docker container'); - - logger.step(3, 'Launching dashboard stop action'); - await dashboard.runAction(constants.GRADLE_9_PROJECT, constants.STOP_DASHBOARD_ACTION, constants.STOP_DASHBOARD_MAC_ACTION); - - logger.step(4, 'Waiting for server to stop'); - const serverStopStatus = await utils.waitForServerStop(constants.SERVER_STOP_STRING); - - if (!serverStopStatus) { - logger.error('Server stopped message not found in the terminal'); - } else { - logger.stepSuccess(4, 'Server stopped successfully'); - } - expect(serverStopStatus).to.be.true; - } - - expect(serverStartStatus).to.be.true; - logger.testComplete('Start Gradle with Docker from Liberty Tools'); - } catch (error) { - logger.testFailed('Start Gradle with Docker from Liberty Tools', error); - throw error; - } - }).timeout(350000); - - it('Run tests for Gradle project', async () => { - logger.testStart('Run tests for Gradle project'); - try { - logger.step(1, 'Launching dashboard start action'); - await dashboard.runAction(constants.GRADLE_9_PROJECT, constants.START_DASHBOARD_ACTION, constants.START_DASHBOARD_MAC_ACTION); - - logger.step(2, 'Waiting for server to start'); - const serverStartStatus = await utils.waitForServerStart(constants.SERVER_START_STRING); - - if (!serverStartStatus) { - logger.error('Server started message not found in the terminal'); - } else { - logger.stepSuccess(2, 'Server successfully started'); - - logger.step(3, 'Launching run tests dashboard action'); - await dashboard.runAction(constants.GRADLE_9_PROJECT, constants.RUNTEST_DASHBOARD_ACTION, constants.RUNTEST_DASHBOARD_MAC_ACTION); - - logger.step(4, 'Checking test execution status'); - const testStatus = await utils.checkTestStatus(constants.GRADLE_TEST_RUN_STRING); - logger.info(`Test status result: ${testStatus}`); - - expect(testStatus).to.be.true; - logger.stepSuccess(4, 'Tests executed successfully'); - - logger.step(5, 'Launching dashboard stop action'); - await dashboard.runAction(constants.GRADLE_9_PROJECT, constants.STOP_DASHBOARD_ACTION, constants.STOP_DASHBOARD_MAC_ACTION); - - logger.step(6, 'Waiting for server to stop'); - const serverStopStatus = await utils.waitForServerStop(constants.SERVER_STOP_STRING); - - if (!serverStopStatus) { - logger.error('Server stopped message not found in the terminal'); - } else { - logger.stepSuccess(6, 'Server stopped successfully'); - } - expect(serverStopStatus).to.be.true; - } - - expect(serverStartStatus).to.be.true; - logger.testComplete('Run tests for Gradle project'); - } catch (error) { - logger.testFailed('Run tests for Gradle project', error); - throw error; - } - }).timeout(350000); - - it('Start Gradle with options from Liberty Tools', async () => { logger.testStart('Start Gradle with options from Liberty Tools'); try { @@ -335,72 +137,6 @@ describe('Open and conduct devmode action tests for Gradle 9.0 Project', () => { } }).timeout(350000); - /** - * All future test cases should be written before the test that attaches the debugger, as this will switch the UI to the debugger view. - * If, for any reason, a test case needs to be written after the debugger test, ensure that the UI is switched back to the explorer view before executing the subsequent tests. - */ - it('Attach debugger for Gradle with custom parameter event', async () => { - logger.testStart('Attach debugger for Gradle with custom parameter event'); - let isServerRunning: Boolean = true; - let attachStatus: Boolean = false; - - try { - logger.step(1, 'Launching dashboard start action with custom parameters'); - await dashboard.runAction(constants.GRADLE_9_PROJECT, constants.START_DASHBOARD_ACTION_WITH_PARAM, constants.START_DASHBOARD_MAC_ACTION_WITH_PARAM); - - logger.step(2, 'Setting custom debug parameter: -DdebugPort=7777'); - await utils.setCustomParameter("-DdebugPort=7777"); - - logger.step(3, 'Waiting for server to start in debug mode'); - isServerRunning = await utils.waitForServerStart(constants.SERVER_START_STRING); - - if (!isServerRunning) { - logger.error('Server started with params message not found in terminal'); - } else { - logger.stepSuccess(3, 'Server successfully started in debug mode'); - - logger.step(4, 'Launching attach debugger dashboard action'); - await dashboard.runAction(constants.GRADLE_9_PROJECT, constants.ATTACH_DEBUGGER_DASHBOARD_ACTION, constants.ATTACH_DEBUGGER_DASHBOARD_MAC_ACTION); - logger.info('Attach Debugger action completed'); - - logger.step(5, 'Waiting for debugger to attach'); - attachStatus = await utils.waitForDebuggerAttach(); - - if (!attachStatus) { - logger.error('DebugToolbar not found - debugger may not have attached'); - } else { - logger.stepSuccess(5, 'Debugger attached successfully'); - } - - logger.step(6, 'Stopping Liberty server'); - await utils.stopLibertyserver(constants.GRADLE_9_PROJECT); - - logger.step(7, 'Waiting for server to stop'); - isServerRunning = !await utils.waitForServerStop(constants.SERVER_STOP_STRING); - - if (!isServerRunning) { - logger.stepSuccess(7, 'Server stopped successfully'); - } else { - logger.error('Server stop message not found in terminal'); - } - } - } catch (e) { - logger.error('Exception occurred during attach debugger test', e); - throw e; - } finally { - logger.info(`Finally block - Server running status: ${isServerRunning}`); - if (isServerRunning) { - logger.info('Attempting to stop server in finally block'); - await utils.stopLibertyserver(constants.GRADLE_9_PROJECT); - } else { - logger.info('Server already stopped, test cleanup complete'); - } - } - - expect(attachStatus).to.be.true; - logger.testComplete('Attach debugger for Gradle with custom parameter event'); - }).timeout(550000); - it('View test report for Gradle project', async () => { logger.testStart('View test report for Gradle project'); @@ -431,7 +167,7 @@ describe('Open and conduct devmode action tests for Gradle 9.0 Project', () => { }).timeout(30000); // Based on the UI testing code, it sometimes selects the wrong command in "command palette", such as choosing "Liberty: Start ..." instead of "Liberty: Start" from the recent suggestions. This discrepancy occurs because we specifically need "Liberty: Start" at that moment. - // Now, clear the command history of the "command palette" to avoid receiving "recently used" suggestions. This action should be performed at the end of Gradle Project tests. + // Now, clear the command history of the "command palette" to avoid receiving "recently used" suggestions. This action should be performed at the end of Gradle 9 Project tests. it('Clear Command Palette', async () => { logger.testStart('Clear Command Palette'); try { @@ -452,6 +188,5 @@ describe('Open and conduct devmode action tests for Gradle 9.0 Project', () => { after(async function() { this.timeout(10000); await utils.closeWorkspace(); - utils.copyScreenshotsToProjectFolder('gradle'); }); -}); \ No newline at end of file +}); From 68d757bc549e01fb54bb9b93029ddc355d5d6fc6 Mon Sep 17 00:00:00 2001 From: Venya Sharma Date: Fri, 26 Jun 2026 16:33:38 -0500 Subject: [PATCH 4/4] added correct copyright --- src/test/Gradle9TestDevModeActions.ts | 3 ++- src/test/GradleTestLSPRestSnippetAndDiagnostic.ts | 5 +++++ src/test/MavenTestLSPRestSnippetAndDiagnostic.ts | 5 +++++ src/test/shared/devModeTestSuite.ts | 5 +++++ src/test/utils/editorUtils.ts | 5 +++++ 5 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/test/Gradle9TestDevModeActions.ts b/src/test/Gradle9TestDevModeActions.ts index 32b5e247..b0777ad9 100644 --- a/src/test/Gradle9TestDevModeActions.ts +++ b/src/test/Gradle9TestDevModeActions.ts @@ -1,7 +1,8 @@ /* * IBM Confidential - * Copyright IBM Corp. 2023, 2026 + * Copyright IBM Corp. 2026 */ + import { expect } from 'chai'; import { runDevModeTestSuite } from "./shared/devModeTestSuite"; import * as utils from './utils/testUtils'; diff --git a/src/test/GradleTestLSPRestSnippetAndDiagnostic.ts b/src/test/GradleTestLSPRestSnippetAndDiagnostic.ts index fa50985f..35634279 100644 --- a/src/test/GradleTestLSPRestSnippetAndDiagnostic.ts +++ b/src/test/GradleTestLSPRestSnippetAndDiagnostic.ts @@ -1,3 +1,8 @@ +/* + * IBM Confidential + * Copyright IBM Corp. 2026 + */ + import * as utils from './utils/testUtils'; import { runRestSnippetSuite } from './shared/restSnippetSuite'; diff --git a/src/test/MavenTestLSPRestSnippetAndDiagnostic.ts b/src/test/MavenTestLSPRestSnippetAndDiagnostic.ts index 96a7a400..9c47e7c3 100644 --- a/src/test/MavenTestLSPRestSnippetAndDiagnostic.ts +++ b/src/test/MavenTestLSPRestSnippetAndDiagnostic.ts @@ -1,3 +1,8 @@ +/* + * IBM Confidential + * Copyright IBM Corp. 2026 + */ + import * as utils from './utils/testUtils'; import { runRestSnippetSuite } from './shared/restSnippetSuite'; diff --git a/src/test/shared/devModeTestSuite.ts b/src/test/shared/devModeTestSuite.ts index 749fcc0f..2f670e28 100644 --- a/src/test/shared/devModeTestSuite.ts +++ b/src/test/shared/devModeTestSuite.ts @@ -1,3 +1,8 @@ +/* + * IBM Confidential + * Copyright IBM Corp. 2026 + */ + import { expect } from 'chai'; import { DefaultTreeItem, EditorView, SideBarView, ViewItem, ViewSection, VSBrowser, Workbench, WebDriver } from 'vscode-extension-tester'; import * as utils from '../utils/testUtils'; diff --git a/src/test/utils/editorUtils.ts b/src/test/utils/editorUtils.ts index 34f63d69..fd991a25 100644 --- a/src/test/utils/editorUtils.ts +++ b/src/test/utils/editorUtils.ts @@ -1,3 +1,8 @@ +/* + * IBM Confidential + * Copyright IBM Corp. 2026 + */ + import { TextEditor, VSBrowser, Workbench } from 'vscode-extension-tester'; import * as utils from './testUtils';