Salesforce: Automate creation of Change Set using Selenium

Have you ever been involved in creation of change set for a release? If the number of components are high, then creation of change set becomes a time consuming process. And then the same change set creation has to be replicated across all the env: dev, QA, UAT and finally on Staging. To avoid all the manual work and save time, I have automated the creation of change set using Selenium. You just need the provide the name of your components in a property file and the application will take care of creating the change set. Currently the application is limited to 3 types of components: Apex class, VF page and Triggers and I will be enhancing it soon to support most of the component types.

To use this application, create a new Java project in eclipse and follow below steps:

1) Copy following classes in src/main folder:
    a) ChangeSet.java
    b) ChangeSetUtils.java
    c) SeleniumUtils.java

2) Create a file named config.properties under src folder and copy the contents given below:

username=provide your sandbox(test.salesforce.com) username here, do not provide username used to login to login.salesforce.com
password=provide your password here
changeSetName=Selenium Test Change Set
apexClass=Class1,Class2 (provide comma separated class names)
vfPage=Page1,Page2 
(provide comma separated vf page names)
apexTrigger=Trigger1,Trigger2,Trigger3 
(provide comma separated trigger names)

3) Download selenium standalone server jar and add it to your classpath

4) Download firefox webdriver and provide the path of downloaded exe in getWebDriver method present in SeleniumUtils class

4) Build the project and run ChangeSet.java class.

Below is the code for all the classes:

1) ChangeSet.java

package main.java;

import java.io.IOException;
import java.util.Properties;
import org.openqa.selenium.WebDriver;

public class ChangeSet {

private static Properties prop;

private static WebDriver wd;

public static void main( String[] args ) throws IOException{

// set base properties
wd = SeleniumUtils.getWebDriver();

// Get properties file
prop = SeleniumUtils.loadPropFile("config.properties");

// login to salesforce
SeleniumUtils.login(wd, prop.getProperty("username"), prop.getProperty("password"));

// create Change set
ChangeSetUtils.createChangeSet(wd,prop);
// go to add components page
ChangeSetUtils.clickOnAddButton(wd);
// add Apex classes
if(prop.getProperty("apexClass") != null){
addComponents("apexClass");
}

// go to add components page
ChangeSetUtils.clickOnAddButton(wd);

//add VF pages
if(prop.getProperty("vfPage") != null){
addComponents("vfPage");
}
// go to add components page
ChangeSetUtils.clickOnAddButton(wd);
//add Apex triggers
if(prop.getProperty("apexTrigger") != null){
addComponents("apexTrigger");
}
}

public static void addComponents(String propertyName){
String componentInfo = prop.getProperty(propertyName);
if(componentInfo.contains(",")){
String[] listofComponent = componentInfo.split(",");
Integer count = 0;
for(String component : listofComponent){
if(count == 0){
addComponent(propertyName, component);
}else{
ChangeSetUtils.clickOnAddButton(wd);
addComponent(propertyName, component);
}
count++;
}
}else{
addComponent(propertyName, componentInfo);
}
}

public static void addComponent(String propertyName, String componentName){
if(propertyName.equals("apexClass")){
ChangeSetUtils.addSFComponent(wd, componentName, "Apex Class", "ApexClass");
}else if(propertyName.equals("vfPage")){
ChangeSetUtils.addSFComponent(wd, componentName, "Visualforce Page", "ApexPage");
}else if(propertyName.equals("apexTrigger")){
ChangeSetUtils.addSFComponent(wd, componentName, "Apex Trigger", "ApexTrigger");
}
}
}


2) ChangeSetUtils.java

package main.java;

import java.io.IOException;
import java.util.Properties;
import org.openqa.selenium.WebDriver;

public class ChangeSet {

private static Properties prop;

private static WebDriver wd;

public static void main( String[] args ) throws IOException{

// set base properties
wd = SeleniumUtils.getWebDriver();

// Get properties file
prop = SeleniumUtils.loadPropFile("config.properties");

// login to salesforce
SeleniumUtils.login(wd, prop.getProperty("username"), prop.getProperty("password"));

// create Change set
ChangeSetUtils.createChangeSet(wd,prop);
// go to add components page
ChangeSetUtils.clickOnAddButton(wd);
// add Apex classes
if(prop.getProperty("apexClass") != null){
addComponents("apexClass");
}

// go to add components page
ChangeSetUtils.clickOnAddButton(wd);

//add VF pages
if(prop.getProperty("vfPage") != null){
addComponents("vfPage");
}
// go to add components page
ChangeSetUtils.clickOnAddButton(wd);
//add Apex triggers
if(prop.getProperty("apexTrigger") != null){
addComponents("apexTrigger");
}
}

public static void addComponents(String propertyName){
String componentInfo = prop.getProperty(propertyName);
if(componentInfo.contains(",")){
String[] listofComponent = componentInfo.split(",");
Integer count = 0;
for(String component : listofComponent){
if(count == 0){
addComponent(propertyName, component);
}else{
ChangeSetUtils.clickOnAddButton(wd);
addComponent(propertyName, component);
}
count++;
}
}else{
addComponent(propertyName, componentInfo);
}
}

public static void addComponent(String propertyName, String componentName){
if(propertyName.equals("apexClass")){
ChangeSetUtils.addSFComponent(wd, componentName, "Apex Class", "ApexClass");
}else if(propertyName.equals("vfPage")){
ChangeSetUtils.addSFComponent(wd, componentName, "Visualforce Page", "ApexPage");
}else if(propertyName.equals("apexTrigger")){
ChangeSetUtils.addSFComponent(wd, componentName, "Apex Trigger", "ApexTrigger");
}
}
}

3) SeleniumUtils.java


package main.java;


import java.io.IOException;
import java.util.NoSuchElementException;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;

public class SeleniumUtils{
public static WebDriver getWebDriver(){
System.setProperty("webdriver.gecko.driver", "C:/Users/Ravi/Downloads/geckodriver-v0.18.0-win32/geckodriver.exe");
WebDriver wd = new FirefoxDriver();
wd.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
return wd;
}
public static Properties loadPropFile(String fileName) throws IOException{
Properties prop= new Properties();
prop.load(ChangeSetUtils.class.getClassLoader().getResourceAsStream(fileName));
return prop;
}

public static void login(WebDriver wd, String userName, String password) {
wd.navigate().to("https://test.salesforce.com");
wd.findElement(By.id("username")).sendKeys(userName);
wd.findElement(By.id("password")).sendKeys(password);
wd.findElement(By.xpath(".//input[@value='Log In to Sandbox']")).click();
}
public static void switchToFrameAndClick(WebDriver wd, String xpath) throws NoSuchElementException{
switchToFrame(wd,xpath);
click(wd,xpath);
}
public static void switchToFrameAndPopulateValues(WebDriver wd, String xpath, String keys){
switchToFrame(wd,xpath);
populateValues(wd,xpath,keys);
}
public static void switchToFrame(WebDriver wd, String xpath){
int size = wd.findElements(By.tagName("iframe")).size();
int index = 0;
for(int i=0; i<=size; i++){
wd.switchTo().frame(i);
int total=wd.findElements(By.xpath(xpath)).size();
System.out.println(total);
if(total == 1){
index = i;
wd.switchTo().defaultContent();
break;
}
wd.switchTo().defaultContent(); //switching back from the iframe
}
wd.switchTo().frame(index);//Switching to the frame
}
public static void click(WebDriver wd, String xpath){
wd.findElement(By.xpath(xpath)).click();
}
public static void populateValues(WebDriver wd, String xpath, String keys){
wd.findElement(By.xpath(xpath)).sendKeys(keys);
}

}

Comments

Popular posts from this blog

Salesforce Lightning: Countdown timer

Salesforce Hacks: System.LimitException: Too many queueable jobs added to the queue: 2

Building an Org Role Hierarchy component in LWC