Skip to content

Commit

Permalink
improved open, close tab/window behavior
Browse files Browse the repository at this point in the history
  • Loading branch information
Bot-Dev-RPA committed Aug 15, 2024
1 parent b1b2a84 commit 433f8bf
Show file tree
Hide file tree
Showing 49 changed files with 426 additions and 157 deletions.
29 changes: 21 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,50 @@
# Browser Automation Package

This browser automation package is designed to simplify web automation tasks for Automation Anywhere.This package retains all the capabilities of the Selenium WebDriver. You can perform actions such as opening the browser, extracting data, inputting values, clicking elements, and working across iframes as needed for your automation tasks.
This browser automation package is designed to simplify web automation tasks for Automation Anywhere.This package
retains all the capabilities of the Selenium WebDriver. You can perform actions such as opening the browser, extracting
data, inputting values, clicking elements, and working across iframes as needed for your automation tasks.

## Demo

![Animation](https://github.com/A360-Tools/Browser-Automation/assets/82057278/ceef22da-fc4d-4ff5-81d4-b202887f9afa)

## Highlights

![activites](https://github.com/A360-Tools/Browser-Automation/assets/82057278/75554df4-902a-49db-a525-2cae2bd4ee0f)

### 1. Automatic Webdriver Management

One of the key enhancements of this package is its ability to automatically detect the browser version being used and download the appropriate webdriver. This eliminates the need for manual configuration and ensures seamless compatibility across various browser versions.
One of the key enhancements of this package is its ability to automatically detect the browser version being used and
download the appropriate webdriver. This eliminates the need for manual configuration and ensures seamless compatibility
across various browser versions.

### 2. Global Session Management

The actions of this package can use a shared session variable, allowing you to reuse the same browser session across multiple bots. This not only improves efficiency but also reduces resource consumption by avoiding the need to open and close browser sessions repeatedly.
The actions of this package can use a shared session variable, allowing you to reuse the same browser session across
multiple bots. This not only improves efficiency but also reduces resource consumption by avoiding the need to open and
close browser sessions repeatedly.

### 3. Handling JavaScript Alerts

Web applications often employ JavaScript alerts for various purposes. This package includes functionality to handle JavaScript alerts, ensuring that your automation scripts can interact with web applications that use them.
Web applications often employ JavaScript alerts for various purposes. This package includes functionality to handle
JavaScript alerts, ensuring that your automation scripts can interact with web applications that use them.

### 4. Enhanced Navigation Options

Navigation within web applications is made more flexible with options to go back, forward, refresh, and open new tabs. These navigation features simplify interaction with complex web workflows.
Navigation within web applications is made more flexible with options to go back, forward, refresh, and open new tabs.
These navigation features simplify interaction with complex web workflows.

### 5. Improved Table Extraction

The package addresses issues related to table extraction from HTML content. It includes fixes and enhancements that make it easier to extract data from tables in web pages.
The package addresses issues related to table extraction from HTML content. It includes fixes and enhancements that make
it easier to extract data from tables in web pages.

## Important Note for Community Edition Control Room Users
- **Warning**: Please be aware that in the Community Edition Control Room, the system does not automatically set the latest version of imported packages as the default. To ensure you are using the latest and fully functional features, you must manually change the package version to the latest version in every bot.


- **Warning**: Please be aware that in the Community Edition Control Room, the system does not automatically set the
latest version of imported packages as the default. To ensure you are using the latest and fully functional features,
you must manually change the package version to the latest version in every bot.

## Building the Project

You can build this project using Gradle with the following command:
Expand Down
10 changes: 5 additions & 5 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ configure(allprojects) {
testNgVersion = '7.9.0'
loggerVersion = '2.20.0'
jnaVersion = '5.3.1'
version '3.2.0'
version '3.3.0'
}
group "$groupName"

Expand All @@ -45,7 +45,7 @@ configure(allprojects) {
artifactName = project.name
group = "$groupName"
author = "Sumit Kumar"
generatePackageWithDateTime = true
generatePackageWithDateTime = false
}

jar.dependsOn commandCodeGen
Expand Down Expand Up @@ -75,8 +75,8 @@ configure(allprojects) {
}

dependencies {
implementation 'org.seleniumhq.selenium:selenium-support:4.22.0'
implementation 'org.seleniumhq.selenium:selenium-edge-driver:4.22.0'
implementation 'org.seleniumhq.selenium:selenium-chrome-driver:4.23.0'
implementation 'org.seleniumhq.selenium:selenium-support:4.23.1'
implementation 'org.seleniumhq.selenium:selenium-edge-driver:4.23.1'
implementation 'org.seleniumhq.selenium:selenium-chrome-driver:4.23.1'
implementation 'org.jsoup:jsoup:1.17.2'
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,57 +6,41 @@
import com.automationanywhere.botcommand.utils.interfaces.WebDriverFactory;
import com.automationanywhere.toolchain.runtime.session.CloseableSessionObject;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WindowType;

import java.util.*;
import java.util.stream.Collectors;

public class BrowserConnection implements CloseableSessionObject {
private static final String EMPTY_STRING = "";
private final String library;
private WebDriver driver;
private Map<String, WebDriverFactory> factoryMap;

public BrowserConnection(String profilePath, String browser, Boolean headless,
String libraryCode, String driverPath, List<String> stringArguments,
Map<String, Object> prefs) {

initializeFactoryMap();
this.library = Optional.ofNullable(libraryCode).orElse(EMPTY_STRING);
List<String> arguments = prepareArguments(profilePath, headless, stringArguments);
prefs = Optional.ofNullable(prefs).orElse(new HashMap<>());

WebDriverFactory factory = factoryMap.get(browser.toUpperCase());
if (factory == null) {
throw new BotCommandException("Unsupported browser type: " + browser);
}
this.driver = factory.createDriver(arguments, prefs, driverPath);
public static final String CHROME = "CHROME";
public static final String EDGE = "EDGE";

if (this.driver == null) {
throw new BotCommandException("Unable to initialize the WebDriver for: " + browser + " browser");
}
}

private void initializeFactoryMap() {
factoryMap = new HashMap<>();
factoryMap.put("CHROME", new ChromeWebDriverFactory());
factoryMap.put("EDGE", new EdgeWebDriverFactory());
}

private List<String> prepareArguments(String profilePath, Boolean headless, List<String> stringArguments) {
List<String> arguments = new ArrayList<>(Optional.ofNullable(stringArguments).orElse(Collections.emptyList()));
arguments.addAll(getDefaultArguments());
if (Optional.ofNullable(headless).orElse(Boolean.FALSE)) {
arguments.add("--headless");
}
Optional.ofNullable(profilePath).filter(path -> !path.isBlank()).ifPresent(path -> arguments.add("user-data" +
"-dir=" + path));
return arguments;
}
private WebDriver driver;
private final String library;

private static List<String> getDefaultArguments() {
return Arrays.stream(DriverDefaultArgument.values())
.map(DriverDefaultArgument::getArgument)
.collect(Collectors.toList());
// New fields to store constructor parameters
private final String browserType;
private final String profilePath;
private final boolean headless;
private final String driverPath;
private final List<String> arguments;

public BrowserConnection(
String browserType,
String profilePath,
boolean headless,
String library,
String driverPath,
List<String> arguments) {

this.browserType = browserType;
this.profilePath = profilePath;
this.headless = headless;
this.driverPath = driverPath;
this.arguments = arguments;
this.library = Optional.ofNullable(library).orElse("");

initializeDriver();
}

public WebDriver getDriver() {
Expand All @@ -76,23 +60,117 @@ public boolean isClosed() {
public void close() {
if (this.driver != null) {
this.driver.quit();
this.driver = null;
}
}

public void reinitializeDriver() {
close();
initializeDriver();
}

private void initializeDriver() {
List<String> driverArguments = prepareDriverArguments(headless, profilePath, arguments);
Map<String, Object> driverPreferences = prepareDriverPreferences();
WebDriverFactory factory = getWebDriverFactory(browserType);
driver = factory.createDriver(driverArguments, driverPreferences, driverPath);
if (driver == null) {
throw new BotCommandException("Unable to initialize the WebDriver.");
}
}

private static WebDriverFactory getWebDriverFactory(String browserType) {
switch (browserType.toUpperCase()) {
case CHROME:
return new ChromeWebDriverFactory();
case EDGE:
return new EdgeWebDriverFactory();
default:
throw new BotCommandException("Unsupported browser type: " + browserType);
}
this.driver = null;
}

public enum DriverDefaultArgument {
private static Map<String, Object> prepareDriverPreferences() {
return new HashMap<>() {{
put(PreferenceKeys.CREDENTIALS_ENABLE_SERVICE.getKey(), false);
put(PreferenceKeys.PASSWORD_MANAGER_ENABLED.getKey(), false);
put(PreferenceKeys.AUTOFILL_PROFILE_ENABLED.getKey(), false);
put(PreferenceKeys.AUTOFILL_CREDIT_CARD_ENABLED.getKey(), false);
put(PreferenceKeys.EXIT_TYPE.getKey(), "Normal");
put(PreferenceKeys.EXITED_CLEANLY.getKey(), true);
}};
}

private static List<String> prepareDriverArguments(boolean headless, String profilePath, List<String> userArguments) {
List<String> defaultArguments = Arrays.stream(DriverArguments.values())
.map(DriverArguments::getArgument)
.collect(Collectors.toList());

List<String> mergedArguments = new ArrayList<>(userArguments != null ? userArguments : new ArrayList<>());
mergedArguments.addAll(defaultArguments.stream()
.filter(arg -> mergedArguments.stream().noneMatch(a -> a.startsWith(arg)))
.collect(Collectors.toList()));

mergedArguments.removeIf(a -> a.equals(DriverArguments.HEADLESS.getArgument()) || a.startsWith(DriverArguments.USER_DATA_DIR.getArgument()));

if (headless) {
mergedArguments.add(DriverArguments.HEADLESS.getArgument());
}

if (profilePath != null && !profilePath.isEmpty()) {
mergedArguments.add(DriverArguments.USER_DATA_DIR.getArgument() + profilePath);
}

return mergedArguments.stream().distinct().collect(Collectors.toList());
}


private void initializeDriver(String driverPath, List<String> arguments, Map<String, Object> preferences, String browserType) {
WebDriverFactory factory = getWebDriverFactory(browserType);
driver = factory.createDriver(arguments, preferences, driverPath);
if (driver == null) {
throw new BotCommandException("Unable to initialize the WebDriver.");
}
}

private enum DriverArguments {
NO_SANDBOX("--no-sandbox"),
DISABLE_SESSION_CRASHED_BUBBLE("--disable-session-crashed-bubble"),
DISABLE_INFOBARS("--disable-infobars"),
DISABLE_RESTORE_SESSION_STATE("--disable-restore-session-state"),
DISABLE_GPU("--disable-gpu"),
IGNORE_CERTIFICATE_ERRORS("--ignore-certificate-errors"),
DISABLE_BLINK_FEATURES("--disable-blink-features=AutomationControlled");
DISABLE_BLINK_FEATURES("--disable-blink-features=AutomationControlled"),
HEADLESS("--headless"),
USER_DATA_DIR("user-data-dir=");

private final String argument;

DriverDefaultArgument(String argument) {
DriverArguments(String argument) {
this.argument = argument;
}

public String getArgument() {
return argument;
}
}
}

private enum PreferenceKeys {
CREDENTIALS_ENABLE_SERVICE("credentials_enable_service"),
PASSWORD_MANAGER_ENABLED("profile.password_manager_enabled"),
AUTOFILL_PROFILE_ENABLED("autofill.profile_enabled"),
AUTOFILL_CREDIT_CARD_ENABLED("autofill.credit_card_enabled"),
EXIT_TYPE("exit_type"),
EXITED_CLEANLY("exited_cleanly");

private final String key;

PreferenceKeys(String key) {
this.key = key;
}

public String getKey() {
return key;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,9 @@ public static void processInputString(String input, Actions action) {
} else {
for (char c : segment.toCharArray()) {
if (capsLockPressed && Character.isLetter(c)) {
if(!shiftPressed ){
if (!shiftPressed) {
action.keyDown(Keys.SHIFT).sendKeys(String.valueOf(c)).keyUp(Keys.SHIFT);
}
else{
} else {
action.keyUp(Keys.SHIFT).sendKeys(String.valueOf(c)).keyDown(Keys.SHIFT);
}
} else {
Expand Down Expand Up @@ -85,8 +84,14 @@ private static Map<String, Consumer<Actions>> initializeSpecialKeys() {
Map<String, Consumer<Actions>> keys = new HashMap<>();
keys.put("[CTRL DOWN]", (a) -> a.keyDown(Keys.CONTROL));
keys.put("[CTRL UP]", (a) -> a.keyUp(Keys.CONTROL));
keys.put("[SHIFT DOWN]", (a) -> {a.keyDown(Keys.SHIFT);shiftPressed = true;});
keys.put("[SHIFT UP]", (a) -> {a.keyUp(Keys.SHIFT);shiftPressed = false;});
keys.put("[SHIFT DOWN]", (a) -> {
a.keyDown(Keys.SHIFT);
shiftPressed = true;
});
keys.put("[SHIFT UP]", (a) -> {
a.keyUp(Keys.SHIFT);
shiftPressed = false;
});
keys.put("[ALT DOWN]", (a) -> a.keyDown(Keys.ALT));
keys.put("[ALT UP]", (a) -> a.keyUp(Keys.ALT));
keys.put("[ALT-GR DOWN]", (a) -> a.keyDown(Keys.CONTROL).keyDown(Keys.ALT));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import org.openqa.selenium.PageLoadStrategy;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeDriverService;
import org.openqa.selenium.chrome.ChromeOptions;

import java.util.Collections;
Expand All @@ -14,20 +15,25 @@
* @author Sumit Kumar
*/
public class ChromeWebDriverFactory implements WebDriverFactory {
private static final String CHROME_DRIVER_SYSTEM_PROPERTY = "webdriver.chrome.driver";

@Override
public WebDriver createDriver(List<String> arguments, Map<String, Object> prefs, String driverPath) {
setDriverPath(driverPath);
ChromeDriverService driverService = createDriverService(driverPath);
ChromeOptions options = new ChromeOptions();
configureOptions(options, arguments, prefs);
return new ChromeDriver(options);
return new ChromeDriver(driverService, options);
}

private void setDriverPath(String driverPath) {
private ChromeDriverService createDriverService(String driverPath) {
ChromeDriverService service;
if (driverPath != null && !driverPath.isBlank()) {
System.setProperty(ChromeWebDriverFactory.CHROME_DRIVER_SYSTEM_PROPERTY, driverPath);
service = new ChromeDriverService.Builder()
.usingDriverExecutable(new java.io.File(driverPath))
.build();
} else {
service = ChromeDriverService.createDefaultService();
}
return service;
}

private void configureOptions(ChromeOptions options, List<String> arguments, Map<String, Object> prefs) {
Expand Down
Loading

0 comments on commit 433f8bf

Please sign in to comment.