diff --git a/src/test/Gradle9TestDevModeActions.ts b/src/test/Gradle9TestDevModeActions.ts index fd8e166a..b0777ad9 100644 --- a/src/test/Gradle9TestDevModeActions.ts +++ b/src/test/Gradle9TestDevModeActions.ts @@ -1,230 +1,33 @@ -// 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 + * Copyright IBM Corp. 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 +138,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 +168,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 +189,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 +}); diff --git a/src/test/GradleTestDevModeActions.ts b/src/test/GradleTestDevModeActions.ts index ad3adb69..8c144a2c 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'); @@ -423,8 +165,6 @@ describe('Devmode action tests for Gradle 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. it('Clear Command Palette', async () => { logger.testStart('Clear Command Palette'); try { @@ -445,6 +185,5 @@ describe('Devmode action tests for Gradle Project', () => { after(async function() { this.timeout(10000); await utils.closeWorkspace(); - utils.copyScreenshotsToProjectFolder('gradle'); }); -}); \ No newline at end of file +}); diff --git a/src/test/GradleTestLSPHover.ts b/src/test/GradleTestLSPHover.ts index 29df7041..b2fa37e2 100644 --- a/src/test/GradleTestLSPHover.ts +++ b/src/test/GradleTestLSPHover.ts @@ -1,187 +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; - } - }); - }); - }); - + ] }); - diff --git a/src/test/GradleTestLSPRestSnippetAndDiagnostic.ts b/src/test/GradleTestLSPRestSnippetAndDiagnostic.ts index c3737817..35634279 100644 --- a/src/test/GradleTestLSPRestSnippetAndDiagnostic.ts +++ b/src/test/GradleTestLSPRestSnippetAndDiagnostic.ts @@ -1,173 +1,9 @@ - /* * 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 { 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; - - 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'); - - 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') { - await VSBrowser.instance.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 * as utils from './utils/testUtils'; +import { runRestSnippetSuite } from './shared/restSnippetSuite'; +runRestSnippetSuite({ buildTool: 'gradle', getProjectPath: utils.getGradleProjectPath }); diff --git a/src/test/MavenTestDevModeActions.ts b/src/test/MavenTestDevModeActions.ts index a5d40caf..18bc54e1 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 { @@ -387,80 +197,10 @@ describe('Devmode action tests for Maven Project', () => { }).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 closes the workspace and copies screenshots. - * Closing the workspace ensures the next test file starts with a clean slate. + * The following after hook closes the workspace so the next test file starts with a clean slate. */ after(async function() { this.timeout(10000); await utils.closeWorkspace(); - utils.copyScreenshotsToProjectFolder('maven'); }); }); - - diff --git a/src/test/MavenTestLSPHover.ts b/src/test/MavenTestLSPHover.ts index c8568945..8c1ccd3b 100644 --- a/src/test/MavenTestLSPHover.ts +++ b/src/test/MavenTestLSPHover.ts @@ -1,196 +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'); - - // Wait for editor to be fully ready and Language Server to attach - await utils.getWaitHelper().sleep(5000); - logger.info('Editor ready for Language Server interaction'); - }); - - 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', - 120 - ); - 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'); - - // Wait for Java editor to be fully ready and Language Server to attach - await utils.getWaitHelper().sleep(10000); - logger.info('Java editor ready for Language Server interaction'); - }); - - 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', - 120 - ); - 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 945c89ce..9c47e7c3 100644 --- a/src/test/MavenTestLSPRestSnippetAndDiagnostic.ts +++ b/src/test/MavenTestLSPRestSnippetAndDiagnostic.ts @@ -1,173 +1,9 @@ - /* * 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 { 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; - - 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'); - - 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') { - await VSBrowser.instance.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 * as utils from './utils/testUtils'; +import { runRestSnippetSuite } from './shared/restSnippetSuite'; +runRestSnippetSuite({ buildTool: 'maven', getProjectPath: utils.getMvnProjectPath }); 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 { diff --git a/src/test/shared/devModeTestSuite.ts b/src/test/shared/devModeTestSuite.ts new file mode 100644 index 00000000..2f670e28 --- /dev/null +++ b/src/test/shared/devModeTestSuite.ts @@ -0,0 +1,303 @@ +/* + * 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'; +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; + } + + }); + }); +} + 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';