diff --git a/src/test/GradleSingleModLCLSTest.ts b/src/test/GradleSingleModLCLSTest.ts
new file mode 100755
index 00000000..f9dcd865
--- /dev/null
+++ b/src/test/GradleSingleModLCLSTest.ts
@@ -0,0 +1,261 @@
+/**
+ * Copyright (c) 2025 IBM Corporation.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+import { By, EditorView, SideBarView, TextEditor, VSBrowser } from "vscode-extension-tester";
+import * as utils from './utils/testUtils';
+import * as constants from './definitions/constants';
+
+const path = require('path');
+const assert = require('assert');
+
+describe('LCLS tests for Gradle Project', function () {
+ let editor: TextEditor;
+ let actualSeverXMLContent: string;
+
+ before(() => {
+ utils.copyConfig(path.join(utils.getGradleProjectPath(), 'src', 'main', 'liberty', 'config'), path.join(utils.getGradleProjectPath(), 'src', 'main', 'liberty', 'config2'));
+ });
+
+ it('Should copy content of server.xml', async () => {
+ const section = await new SideBarView().getContent().getSection(constants.GRADLE_PROJECT);
+ section.expand();
+ await VSBrowser.instance.openResources(path.join(utils.getGradleProjectPath(), 'src', 'main', 'liberty', 'config2', 'server.xml'));
+
+ editor = await new EditorView().openEditor('server.xml') as TextEditor;
+ actualSeverXMLContent = await editor.getText();
+
+ assert(actualSeverXMLContent.length !== 0, 'Content of server.xml is not in copied.');
+ console.log('Sever.xml content:', actualSeverXMLContent);
+
+ }).timeout(10000);
+
+ it('Should show diagnostic for server.xml invalid value', async () => {
+
+ await VSBrowser.instance.openResources(path.join(utils.getGradleProjectPath(), 'src', 'main', 'liberty', 'config2', 'server.xml'));
+ editor = await new EditorView().openEditor('server.xml') as TextEditor;
+
+ const hverExpectdOutcome = `'wrong' is not a valid value of union type 'booleanType'.`;
+ const testHverTarget = '';
+
+ await editor.typeTextAt(17, 5, testHverTarget);
+ const focusTargtElemnt = editor.findElement(By.xpath("//*[contains(text(), 'wrong')]"));
+ await utils.delay(3000);
+ focusTargtElemnt.click();
+ await editor.click();
+
+ const actns = VSBrowser.instance.driver.actions();
+ await actns.move({ origin: focusTargtElemnt }).perform();
+ await utils.delay(5000);
+
+ const hverContent = editor.findElement(By.className('hover-contents'));
+ const hverValue = await hverContent.getText();
+ console.log("Hover text:" + hverValue);
+
+ assert(hverValue.includes(hverExpectdOutcome), 'Did not get expected diagnostic in server.xml');
+
+ editor.clearText();
+ editor.setText(actualSeverXMLContent);
+ console.log("Content restored");
+
+ }).timeout(35000);
+
+ it('Should apply quick fix for invalid value in server.xml', async () => {
+ const section = await new SideBarView().getContent().getSection(constants.GRADLE_PROJECT);
+ section.expand();
+ await VSBrowser.instance.openResources(path.join(utils.getGradleProjectPath(), 'src', 'main', 'liberty', 'config2', 'server.xml'));
+
+ editor = await new EditorView().openEditor('server.xml') as TextEditor;
+ const stanzaSnipet = "";
+ const expectedHoverData = "";
+ await editor.typeTextAt(17, 5, stanzaSnipet);
+ await utils.delay(2000);
+ const flagedString = await editor.findElement(By.xpath("//*[contains(text(), '\"wrong\"')]"));
+ await utils.delay(7000);
+
+ const actions = VSBrowser.instance.driver.actions();
+ await actions.move({ origin: flagedString }).perform();
+ await utils.delay(3000);
+
+ const driver = VSBrowser.instance.driver;
+ const hoverTxt = await editor.findElement(By.className('hover-row status-bar'));
+ await utils.delay(2000);
+
+ const qckFixPopupLink = await hoverTxt.findElement(By.xpath("//*[contains(text(), 'Quick Fix')]"));
+ await qckFixPopupLink.click();
+
+ const hoverTaskBar = await editor.findElement(By.className('context-view monaco-component bottom left fixed'));
+ await hoverTaskBar.findElement(By.className('actionList'));
+ await utils.delay(2000);
+
+ const pointerBlockedElement = await driver.findElement(By.css('.context-view-pointerBlock'));
+ // Setting pointer block element display value as none to choose option from Quickfix menu
+ if (pointerBlockedElement) {
+ await driver.executeScript("arguments[0].style.display = 'none';", pointerBlockedElement);
+ } else {
+ console.log('pointerBlockElementt not found!');
+ }
+ const qckfixOption = await editor.findElement(By.xpath("//*[contains(text(), \"Replace with 'true'\")]"));
+ await qckfixOption.click();
+
+ const updatedSeverXMLContent = await editor.getText();
+ await utils.delay(3000);
+ console.log("Content after Quick fix : ", updatedSeverXMLContent);
+ assert(updatedSeverXMLContent.includes(expectedHoverData), 'Quick fix not applied correctly for the invalid value in server.xml.');
+
+ editor.clearText();
+ editor.setText(actualSeverXMLContent);
+ console.log("Content restored");
+
+ }).timeout(38000);
+
+ it('Should show hover support for server.xml Liberty Server Attribute', async () => {
+
+ await VSBrowser.instance.openResources(path.join(utils.getGradleProjectPath(), 'src', 'main', 'liberty', 'config2', 'server.xml'));
+ editor = await new EditorView().openEditor('server.xml') as TextEditor;
+
+ const hovrExpctdOutcome = `Configuration properties for an HTTP endpoint.`;
+
+ console.log(hovrExpctdOutcome);
+ const focusTargtElemnt = editor.findElement(By.xpath("//*[contains(text(), 'httpEndpoint')]"));
+ await utils.delay(3000);
+ focusTargtElemnt.click();
+ await editor.click();
+
+ const actns = VSBrowser.instance.driver.actions();
+ await actns.move({ origin: focusTargtElemnt }).perform();
+ await utils.delay(5000);
+
+ const hverContent = editor.findElement(By.className('hover-contents'));
+ const hoveredText = await hverContent.getText();
+ console.log("Hover text:" + hoveredText);
+
+ assert(hoveredText.includes(hovrExpctdOutcome), 'Did not get expected hover data Liberty Server Attribute.');
+
+ editor.clearText();
+ editor.setText(actualSeverXMLContent);
+ console.log("Content restored");
+
+ }).timeout(35000);
+
+ it('Should show hover support for server.xml Liberty Server Feature', async () => {
+
+ await VSBrowser.instance.openResources(path.join(utils.getGradleProjectPath(), 'src', 'main', 'liberty', 'config2', 'server.xml'));
+ editor = await new EditorView().openEditor('server.xml') as TextEditor;
+
+ const hverExpectdOutcome = `Description: This feature provides support for the MicroProfile Health specification.`;
+ const testHverTarget = 'mpHealth-4.0';
+
+ await editor.typeTextAt(15, 35, '\n');
+ await utils.delay(1000);
+ await editor.typeTextAt(16, 9, testHverTarget);
+ const focusTargtElemnt = editor.findElement(By.xpath("//*[contains(text(), 'mpHealth')]"));
+ await utils.delay(3000);
+ focusTargtElemnt.click();
+ await editor.click();
+
+ const actns = VSBrowser.instance.driver.actions();
+ await actns.move({ origin: focusTargtElemnt }).perform();
+ await utils.delay(5000);
+
+ const hverContent = editor.findElement(By.className('hover-contents'));
+ const hverValue = await hverContent.getText();
+ console.log("Hover text:" + hverValue);
+
+ assert(hverValue.includes(hverExpectdOutcome), 'Did not get expected hover data Liberty Server Feature.');
+
+ editor.clearText();
+ editor.setText(actualSeverXMLContent);
+ console.log("Content restored");
+
+ }).timeout(33000);
+
+ it('Should show type ahead support in server.xml Liberty Server Feature', async () => {
+ const section = await new SideBarView().getContent().getSection(constants.GRADLE_PROJECT);
+ section.expand();
+ await VSBrowser.instance.openResources(path.join(utils.getGradleProjectPath(), 'src', 'main', 'liberty', 'config2', 'server.xml'));
+
+ editor = await new EditorView().openEditor('server.xml') as TextEditor;
+ const featureTag = " {
+ const section = await new SideBarView().getContent().getSection(constants.GRADLE_PROJECT);
+ section.expand();
+ await VSBrowser.instance.openResources(path.join(utils.getGradleProjectPath(), 'src', 'main', 'liberty', 'config2', 'server.xml'));
+
+ editor = await new EditorView().openEditor('server.xml') as TextEditor;
+ const stanzaSnipet = "log";
+
+ const insertedConfig = "";
+ await editor.typeTextAt(17, 5, stanzaSnipet);
+ await utils.delay(5000);
+ //open the assistant
+ let asist = await editor.toggleContentAssist(true);
+ // toggle can return void, so we need to make sure the object is present
+ if (asist) {
+ // to select an item use
+ await asist.select('logging')
+ }
+ // close the assistant
+ await editor.toggleContentAssist(false);
+
+ // close the assistant
+ await editor.toggleContentAssist(false);
+
+ const updatedServerxmlContent = await editor.getText();
+ await utils.delay(3000);
+ console.log("Updated content in Sever.xml : ", updatedServerxmlContent);
+ assert(updatedServerxmlContent.includes(insertedConfig), 'Type ahead support is not worked as expected in server.xml Liberty Server Configuration Stanza');
+
+ editor.clearText();
+ editor.setText(actualSeverXMLContent);
+ console.log("Content restored");
+
+ }).timeout(25000);
+
+ after(() => {
+ utils.removeConfigDir(path.join(utils.getGradleProjectPath(), 'src', 'main', 'liberty', 'config2'));
+ console.log("Removed new config folder:");
+ });
+
+});
\ No newline at end of file
diff --git a/src/test/utils/testUtils.ts b/src/test/utils/testUtils.ts
index a2a0135b..ddbd7a34 100755
--- a/src/test/utils/testUtils.ts
+++ b/src/test/utils/testUtils.ts
@@ -5,6 +5,7 @@ import { MAVEN_PROJECT, STOP_DASHBOARD_MAC_ACTION } from '../definitions/consta
import { MapContextMenuforMac } from './macUtils';
import clipboard = require('clipboardy');
import { expect } from 'chai';
+import * as fse from 'fs-extra';
export function delay(millisec: number) {
return new Promise( resolve => setTimeout(resolve, millisec) );
@@ -192,4 +193,36 @@ export async function clearCommandPalette() {
expect(buttons.length).equals(2);
await dialog.pushButton('Clear');
}
-
\ No newline at end of file
+
+/**
+ * Remove newly created Project folder with content
+ */
+export async function removeConfigDir(projectPath: string): Promise {
+ try {
+ fs.accessSync(projectPath);
+ const projectContent = fs.readdirSync(projectPath);
+ await Promise.all(
+ projectContent.map(async (projectFiles) => {
+ const projectContentPath = path.join(projectPath, projectFiles);
+ const stats = fs.lstatSync(projectContentPath);
+ if (stats.isDirectory()) {
+ await removeConfigDir(projectContentPath);
+ } else {
+ fs.unlinkSync(projectContentPath);
+ }
+ })
+ );
+ fs.rmdirSync(projectPath);
+ } catch (error) {
+ console.error(`Error removing new project: ${error}`);
+ }
+}
+
+/**
+ * Copy config directory and create new config
+ */
+export async function copyConfig(existingConfigPath: string, copyConfigPath: string): Promise {
+ fse.copy(existingConfigPath, copyConfigPath)
+ .then(() => console.log("New config folder created :" + copyConfigPath))
+ .catch(err => console.log("Error creating config folder"));
+}
\ No newline at end of file