|
| 1 | +import * as path from 'path'; |
| 2 | +import { logger } from '../utils/testLogger'; |
| 3 | +import { EditorView, VSBrowser, WebDriver } from 'vscode-extension-tester'; |
| 4 | +import { EditorPage } from '../pages/EditorPage'; |
| 5 | +import * as utils from '../utils/testUtils'; |
| 6 | +import { expect } from 'chai'; |
| 7 | +import { CodeAssistPage } from '../pages/CodeAssistPage'; |
| 8 | +import { ProblemsPage } from '../pages/ProblemsPage'; |
| 9 | +import { QuickFixPage } from '../pages/QuickFixPage'; |
| 10 | + |
| 11 | +export interface ServerEnvConfig { |
| 12 | + buildTool: 'maven' | 'gradle'; |
| 13 | + getProjectPath: () => string; |
| 14 | + hoverTestCases: Array<{ |
| 15 | + element: string; |
| 16 | + line: number; |
| 17 | + column: number; |
| 18 | + expectedDoc: string; |
| 19 | + }>; |
| 20 | +} |
| 21 | + |
| 22 | +export function runServerEnvSuite(config: ServerEnvConfig){ |
| 23 | + describe(`Server Env functionality tests for ${config.buildTool === 'maven' ? 'Maven' : 'Gradle'} Project`, () => { |
| 24 | + // Compute the test file path using config |
| 25 | + let serverEnv : EditorPage; |
| 26 | + let wait: any; |
| 27 | + |
| 28 | + before(async function() { |
| 29 | + this.timeout(60000); |
| 30 | + |
| 31 | + logger.info(`Setting up ${config.buildTool === 'maven' ? 'Maven' : 'Gradle'} LSP Hover tests`); |
| 32 | + |
| 33 | + // Wait for workbench to be ready |
| 34 | + await VSBrowser.instance.openResources(config.getProjectPath()); |
| 35 | + await VSBrowser.instance.waitForWorkbench(); |
| 36 | + |
| 37 | + wait = utils.getWaitHelper(); |
| 38 | + |
| 39 | + logger.info('Opening server.env file for all tests'); |
| 40 | + const serverEnvPath = path.resolve( |
| 41 | + config.getProjectPath(), |
| 42 | + 'src', |
| 43 | + 'main', |
| 44 | + 'liberty', |
| 45 | + 'config', |
| 46 | + 'server.env' |
| 47 | + ); |
| 48 | + logger.info(`Server.env path: ${serverEnvPath}`); |
| 49 | + |
| 50 | + serverEnv = await new EditorPage().openFile(serverEnvPath, 'server.env'); |
| 51 | + logger.info('Server.env file opened and editor obtained'); |
| 52 | + }); |
| 53 | + |
| 54 | + afterEach(async function() { |
| 55 | + // Take screenshot on failure but don't close editor |
| 56 | + if (this.currentTest?.state === 'failed') { |
| 57 | + await VSBrowser.instance.driver.takeScreenshot(); |
| 58 | + logger.error(`Test failed: ${this.currentTest.title}`); |
| 59 | + } |
| 60 | + }); |
| 61 | + |
| 62 | + after(async function() { |
| 63 | + this.timeout(10000); // Increase timeout for cleanup operations |
| 64 | + // Clear server.env file, same logic as in restSnippetSuite.ts |
| 65 | + try { |
| 66 | + if (serverEnv) { |
| 67 | + // Select all text first, then clear |
| 68 | + const currentText = await serverEnv.getEditor().getText(); |
| 69 | + try { |
| 70 | + await serverEnv.getEditor().selectText(currentText); |
| 71 | + await wait.sleep(300); |
| 72 | + } catch (selectError) { |
| 73 | + // selectText may fail but setText still works |
| 74 | + } |
| 75 | + |
| 76 | + await serverEnv.clear(); |
| 77 | + logger.info('Reset TestRest.java to empty after test'); |
| 78 | + } |
| 79 | + } catch (error) { |
| 80 | + logger.error('Failed to reset TestRest.java', error); |
| 81 | + } |
| 82 | + // Close editor after all tests complete |
| 83 | + try { |
| 84 | + await new EditorView().closeAllEditors(); |
| 85 | + logger.info('Closed all editors after test suite'); |
| 86 | + } catch (error) { |
| 87 | + logger.error('Failed to close editors in after hook', error); |
| 88 | + } |
| 89 | + |
| 90 | + utils.copyScreenshotsToProjectFolder(config.buildTool); |
| 91 | + }); |
| 92 | + |
| 93 | + it('Liberty Language Server should initialize', async function() { |
| 94 | + this.timeout(60000); |
| 95 | + logger.testStart('Liberty Language Server should initialize'); |
| 96 | + |
| 97 | + try { |
| 98 | + await utils.waitForLanguageServerInit( |
| 99 | + 'Language Support for Liberty', |
| 100 | + 'Initialized Liberty Language server', |
| 101 | + 60 |
| 102 | + ); |
| 103 | + logger.testComplete('Liberty Language Server initialized successfully'); |
| 104 | + } catch (error) { |
| 105 | + logger.testFailed('Liberty Language Server should initialize', error); |
| 106 | + throw error; |
| 107 | + } |
| 108 | + }); |
| 109 | + |
| 110 | + const hoverTestCases = config.hoverTestCases; |
| 111 | + |
| 112 | + hoverTestCases.forEach(testCase => { |
| 113 | + it(`Hover over ${testCase.element} shows Liberty Language Server documentation`, async function() { |
| 114 | + this.timeout(30000); |
| 115 | + logger.testStart(`Hover over ${testCase.element} shows Liberty Language Server documentation`); |
| 116 | + await serverEnv.getEditor().setText('WLP_USER_DIR=/opt/wlp/usr\nLOG_DIR=/logs\n'); |
| 117 | + await serverEnv.getEditor().save(); |
| 118 | + await wait.sleep(1000); |
| 119 | + |
| 120 | + try { |
| 121 | + |
| 122 | + const hoverText = await serverEnv.hoverOver(testCase.line, testCase.column, testCase.element); |
| 123 | + expect(hoverText).to.not.be.empty; |
| 124 | + logger.stepSuccess(3, `Hover widget displayed with Liberty Language Server content for ${testCase.element}`); |
| 125 | + |
| 126 | + logger.step(4, 'Verifying hover contains expected documentation'); |
| 127 | + expect(hoverText).to.include(testCase.expectedDoc); |
| 128 | + logger.stepSuccess(4, `Hover text contains expected documentation: "${testCase.expectedDoc}"`); |
| 129 | + |
| 130 | + logger.testComplete(`Hover over ${testCase.element} shows Liberty Language Server documentation`); |
| 131 | + } catch (error) { |
| 132 | + logger.testFailed(`Hover over ${testCase.element} shows Liberty Language Server documentation`, error); |
| 133 | + throw error; |
| 134 | + } |
| 135 | + }); |
| 136 | + }); |
| 137 | + |
| 138 | + it('server.env WLP_LOG populates correct WLP_LOGGING_MESSAGE_FORMAT type ahead', async function () { |
| 139 | + this.timeout(275000); |
| 140 | + logger.testStart('server.env WLP_LOG populates correct WLP_LOGGING_MESSAGE_FORMAT type ahead'); |
| 141 | + |
| 142 | + try { |
| 143 | + logger.step(1, 'Positioning cursor'); |
| 144 | + await serverEnv.getEditor().setCursor(3, 1); |
| 145 | + |
| 146 | + logger.step(2, 'Opening content assist'); |
| 147 | + const codeAssist = new CodeAssistPage(); |
| 148 | + await codeAssist.insertSnippet(serverEnv, 'WLP_LOG', 'WLP_LOGGING_MESSAGE_FORMAT'); |
| 149 | + logger.stepSuccess(2, 'Completion inserted'); |
| 150 | + const after = await serverEnv.getEditor().getText(); |
| 151 | + expect(after).to.include('WLP_LOGGING_MESSAGE_FORMAT'); |
| 152 | + await wait.sleep(1000); |
| 153 | + |
| 154 | + const lineText = await serverEnv.getEditor().getTextAtLine(3); |
| 155 | + await serverEnv.getEditor().setTextAtLine(3, lineText.trimEnd() + '=JSON'); |
| 156 | + |
| 157 | + await serverEnv.getEditor().save(); |
| 158 | + await wait.sleep(500); |
| 159 | + |
| 160 | + |
| 161 | + logger.testComplete('server.env WLP_LOG populates correct WLP_LOGGING_MESSAGE_FORMAT completion'); |
| 162 | + } catch (error) { |
| 163 | + logger.testFailed('server.env WLP_LOG populates correct WLP_LOGGING_MESSAGE_FORMAT completion', error); |
| 164 | + throw error; |
| 165 | + } |
| 166 | + }); |
| 167 | + it('Show that INVALID text displays diagnostic and quick fix removes it ', async function () { |
| 168 | + this.timeout(90000); |
| 169 | + logger.testStart('Show that INVALID text displays diagnostic and quick fix removes it'); |
| 170 | + try { |
| 171 | + |
| 172 | + await serverEnv.replaceTextWithinLineContaining('WLP_LOGGING_MESSAGE_FORMAT', 'JSON' , 'INVALID'); |
| 173 | + |
| 174 | + // Save file and wait for reanalysis |
| 175 | + await serverEnv.getEditor().save(); |
| 176 | + await wait.sleep(500); |
| 177 | + |
| 178 | + // Check that the diagnostic is there |
| 179 | + let problems = new ProblemsPage(); |
| 180 | + const found = await problems.hasDiagnostic('The value `INVALID` is not valid for the variable `WLP_LOGGING_MESSAGE_FORMAT`.'); |
| 181 | + expect(found).to.be.true; |
| 182 | + logger.testComplete('Diagnostic shows INVALID variable'); |
| 183 | + |
| 184 | + // Quick fix implementation to get rid of diagnostic |
| 185 | + // Re-find line and place cursor on "methodname()" |
| 186 | + const buffer = await serverEnv.getEditor().getText(); |
| 187 | + logger.info('Buffer before quick fix: ' + JSON.stringify(buffer)); |
| 188 | + |
| 189 | + await new QuickFixPage().applyFix(serverEnv, 'INVALID', 'Replace value with JSON'); |
| 190 | + await wait.sleep(3000); |
| 191 | + await serverEnv.getEditor().save(); |
| 192 | + await wait.sleep(5000); |
| 193 | + |
| 194 | + const after = await serverEnv.getEditor().getText(); |
| 195 | + expect(after).to.include('JSON'); |
| 196 | + expect(await problems.hasDiagnostic('The value `INVALID` is not valid for the variable `WLP_LOGGING_MESSAGE_FORMAT`.')).to.be.false; |
| 197 | + |
| 198 | + } catch (error) { |
| 199 | + logger.testFailed('Diagnostic/quick-fix test flow failed', error); |
| 200 | + throw error; |
| 201 | + } |
| 202 | + |
| 203 | + }); |
| 204 | + |
| 205 | + |
| 206 | + |
| 207 | + |
| 208 | + |
| 209 | + |
| 210 | + |
| 211 | + }); |
| 212 | +} |
0 commit comments