Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ jobs:
- runtime: linux
os: ubuntu-latest
- runtime: mac
os: macOS-14
os: macOS-latest
- runtime: windows
os: windows-latest
- test-group: Maven-MicroProfile
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*******************************************************************************
* 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
*******************************************************************************/
package io.openliberty.tools.intellij.it;

import com.intellij.remoterobot.RemoteRobot;
import com.automation.remarks.junit5.Video;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.condition.EnabledOnOs;
import org.junit.jupiter.api.condition.OS;

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BaseOSUtilities {

/**
* URL to display the UI Component hierarchy. This is used to obtain xPath related
* information to find UI components.
*/
public static final String REMOTE_BOT_URL = "http://localhost:8082";

/**
* The remote robot object.
*/
public static final RemoteRobot remoteRobot = new RemoteRobot(REMOTE_BOT_URL);

/**
* Test to handle macOS permission popup if it appears
*/
@Order(1)
@Test
@Video
@EnabledOnOs({OS.MAC})
public void AllowPopupTest() {
UIBotTestUtils.handleMacOSPermissionPopup(remoteRobot);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

import static com.intellij.remoterobot.utils.RepeatUtilsKt.waitForIgnoringError;

public abstract class SingleModJakartaLSTestCommon {
public abstract class SingleModJakartaLSTestCommon extends BaseOSUtilities {
public static final String REMOTEBOT_URL = "http://localhost:8082";
public static final RemoteRobot remoteRobot = new RemoteRobot(REMOTEBOT_URL);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

import static com.intellij.remoterobot.utils.RepeatUtilsKt.waitForIgnoringError;

public abstract class SingleModLibertyLSTestCommon {
public abstract class SingleModLibertyLSTestCommon extends BaseOSUtilities {
public static final String REMOTEBOT_URL = "http://localhost:8082";
public static final RemoteRobot remoteRobot = new RemoteRobot(REMOTEBOT_URL);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2023, 2024 IBM Corporation.
* Copyright (c) 2023, 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
Expand All @@ -21,7 +21,7 @@

import static com.intellij.remoterobot.utils.RepeatUtilsKt.waitForIgnoringError;

public abstract class SingleModMPLSTestCommon {
public abstract class SingleModMPLSTestCommon extends BaseOSUtilities {
public static final String REMOTEBOT_URL = "http://localhost:8082";
public static final RemoteRobot remoteRobot = new RemoteRobot(REMOTEBOT_URL);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,14 @@
import org.junit.jupiter.api.*;

import java.io.File;
import java.nio.file.Paths;
import java.time.Duration;

import static com.intellij.remoterobot.utils.RepeatUtilsKt.waitForIgnoringError;

/**
* Holds common tests that use a single module MicroProfile project.
*/
public abstract class SingleModMPProjectCfgTestCommon {
public abstract class SingleModMPProjectCfgTestCommon extends BaseOSUtilities {

// In this test case the environment has been set up so that there is a new project
// that has not been used in a previous execution of IntelliJ. Also, the Liberty explorer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
/**
* Holds common tests that use a single module MicroProfile project.
*/
public abstract class SingleModMPProjectTestCommon {
public abstract class SingleModMPProjectTestCommon extends BaseOSUtilities {

/**
* URL to display the UI Component hierarchy. This is used to obtain xPath related
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
/**
* Holds common tests that use a single module non Liberty Tools compliant REST project.
*/
public abstract class SingleModNLTRestProjectTestCommon {
public abstract class SingleModNLTRestProjectTestCommon extends BaseOSUtilities {

/**
* URL to display the UI Component hierarchy. This is used to obtain xPath related
Expand Down
62 changes: 60 additions & 2 deletions src/test/java/io/openliberty/tools/intellij/it/UIBotTestUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ public static void closeLibertyToolWindow(RemoteRobot remoteRobot) {
*/
public static void openProjectView(RemoteRobot remoteRobot) {
// maximize windows os intellij ide to avoid failures accessing menu
if (remoteRobot.isWin()) {
if (remoteRobot.isWin() || remoteRobot.isMac()) {
maximizeWindow(remoteRobot);
}
TestUtils.printTrace(TestUtils.TraceSevLevel.INFO, "UIBotTestUtils.openProjectView Entry");
Expand Down Expand Up @@ -1080,7 +1080,11 @@ else if (fileName.equals("bootstrap.properties")) {
// we will put new config at the end of the config file
// (after the last line already in the file)
keyboard.hotKey(VK_CONTROL, VK_END);
// Move to the end of the current line to ensure we're at the end of the last line
keyboard.hotKey(VK_END);
keyboard.enter();
// Wait for the editor to process the newline before typing
TestUtils.sleepAndIgnoreException(1);

keyboard.enterText(configNameSnippetCaseSpecific);
// After typing it can take 1 or 2s for IntelliJ to render diagnostics etc. Must wait before continuing.
Expand Down Expand Up @@ -2851,7 +2855,12 @@ public static void rightClickCloseOnFileTab(RemoteRobot remoteRobot, String file
public static void maximizeWindow(RemoteRobot remoteRobot) {
if (!isFullScreen(remoteRobot)) {
Keyboard keyboard = new Keyboard(remoteRobot);
keyboard.hotKey(VK_WINDOWS, VK_UP);
if (remoteRobot.isWin()) {
keyboard.hotKey(VK_WINDOWS, VK_UP);
} else {
// macOS fullscreen shortcut: Command + Control + F
keyboard.hotKey(VK_META, VK_CONTROL, VK_F);
}
keyboard.enter();
}
}
Expand Down Expand Up @@ -2939,4 +2948,53 @@ public static void clickOnLoad(RemoteRobot remoteRobot) {

TestUtils.sleepAndIgnoreException(5);
}

/**
* Handles macOS permission popup for screen recording by clicking the "Allow" button.
*
* <p>This AppleScript implementation is adapted from community examples on handling macOS security dialogs:
* https://smartwatermelon.medium.com/automating-macos-security-dialogs-a-tale-of-yak-shaving-and-applescript-759300d6fba9
*
* <p>For official documentation on UI scripting and accessibility automation, refer to:
* Apple – Automate the User Interface:
* https://developer.apple.com/library/archive/documentation/LanguagesUtilities/Conceptual/MacAutomationScriptingGuide/AutomatetheUserInterface.html
*
*
* @param remoteRobot The RemoteRobot instance.
*/
public static void handleMacOSPermissionPopup(RemoteRobot remoteRobot) {
if (!remoteRobot.isMac()) {
return; // Only applicable to macOS
}
TestUtils.printTrace(TestUtils.TraceSevLevel.INFO, "Handling macOS permission popup...");

// Wait for the permission popup to appear
TestUtils.sleepAndIgnoreException(10);
// Execute AppleScript to click the "Allow" button
try {
String appleScript =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to cite the source that was used as reference for this "Apple script". You can mention that the appleScript is based off an example provided at https://smartwatermelon.medium.com/automating-macos-security-dialogs-a-tale-of-yak-shaving-and-applescript-759300d6fba9. It would also be good to point to official documentation, like the one you shared here: https://developer.apple.com/library/archive/documentation/LanguagesUtilities/Conceptual/MacAutomationScriptingGuide/AutomatetheUserInterface.html - just in case a developer in the future needs to make changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added these references.

"tell application \"System Events\"\n" +
" tell process \"UserNotificationCenter\"\n" +
" if exists window 1 then\n" +
" try\n" +
" set dialogText to value of static text 1 of window 1\n" +
" if dialogText contains \"bash\" and dialogText contains \"screen and audio\" then\n" +
" if exists button \"Allow\" of window 1 then\n" +
" click button \"Allow\" of window 1\n" +
" end if\n" +
" end if\n" +
" end try\n" +
" end if\n" +
" end tell\n" +
"end tell";

new ProcessBuilder("osascript", "-e", appleScript).start();

// Wait a moment for the click to take effect
TestUtils.sleepAndIgnoreException(5);

} catch (Exception e) {
TestUtils.printTrace(TestUtils.TraceSevLevel.ERROR, "Failed to execute AppleScript: " + e.getMessage());
}
}
}