Skip links

How To Create Objects During Salesforce Automation Testing: UI and CLI Methods

In this article, I am continuing to share the approaches I use during Salesforce automation testing. For a better understanding, I recommend reading my previous article on how to get existing Salesforce data using UI and CLI. 

In Salesforce orgs, most of the functionality relies on either standard or custom objects. Naturally, these objects must be created to work with them. In some cases, this process should be tested step by step, especially when the creation of these objects involves custom logic, such as Lightning web components or Flows.

If your tests don’t require checking the process of object creation, but the exact test case requires the existence of such an object, you can just create an object via the Salesforce CLI tool. 

To some extent, it will decrease the time of test execution because your test will skip some tests with UI interactions.

Let’s explore the hands-on example. We have a test case: The “Convert Lead” window opens while clicking the “Blink Convert” button.

Steps are:

  1. Open Blink application
  2. Click the “Leads” tab
  3. Create a Lead object
  4. Choose created Lead 
  5. Click on the “Blink Convert” button

Expected result: The “Convert Lead” window has been opened. 

Salesforce Object Creation via UI Interface

Let’s automate this test case with a UI approach only.

Firstly, we should log in to our org successfully. To do it, follow the instructions from my previous article

it('open Salesforce instance', async () => {
    await browser.url(frontdoor)
    await expect(browser).toHaveTitle('Lightning Experience | Salesforce')
})

The second step is navigating to the Lead tab. For that, we find it on the navigation bar and click. 

it('open Lead tab', async () => {
    let leadTab = await $(`>>>one-app-nav-bar-item-root[data-id="Lead"]`)
    await leadTab.click()
    await expect(browser).toHaveTitleContaining('| Leads | Salesforce')
})

The next action is creating a new Lead object. Here, we will find and click “New”. When the New Lead window has been opened successfully, we will fill in all nessesary fields (in our case, First Name, Last Name, Company, and Website) and click “Save”.

it('click New button and create new Lead object', async () => {
    let newButton = await $(`>>>[data-target-selection-name="sfdc:StandardButton.Lead.New"]`)
    await newButton.click()
    let modalWindow = await $(`>>>records-lwc-detail-panel`)
    await expect(await modalWindow).toBeDisplayed()
    let firstNameInput = await $(`>>>input[name="firstName"]`)
    let lastNameInput = await $(`>>>input[name="lastName"]`)
    let companyInput = await $(`>>>input[name="Company"]`)
    let websiteInput = await $(`>>>input[name="Website"]`)
    await firstNameInput.addValue(lead.firstName)
    await lastNameInput.addValue(lead.lastName)
    await companyInput.addValue(lead.company)
    await websiteInput.addValue(lead.website)
    let saveButton = await $(`>>>lightning-button [name="SaveEdit"]`)
    await saveButton.click()
    await expect(browser).toHaveTitle(`${lead.firstName} ${lead.lastName} | Lead | Salesforce`)
    let leadNameText = await $(`>>>[slot="primaryField"]`).getText()
    await expect(await leadNameText).toBe(`${lead.firstName} ${lead.lastName}`)
})

After successfully saving, the created Lead will be opened automatically, so we needn’t find it manually.

Finally, we can check the “Blink Convert” functionality. Let’s find and click this button.

it('click Blink Convert button', async () => {
    let layoutButtonsBlock = await $(`>>>.slds-button-group-list`)
    await expect(layoutButtonsBlock).toBeDisplayed()
    let layoutButtonsShowMore = await layoutButtonsBlock.$(`>>>li.slds-button_last`)
    await layoutButtonsShowMore.waitForExist({ timeout: 5000 })
    if (await $(`>>>[title="Blink Convert"] lightning-button`).isDisplayed()) {
        await $(`>>>[title="Blink Convert"] lightning-button`).click()
    } else {
        await layoutButtonsShowMore.click()
        if (await $(`>>>[title="Blink Convert"]`).isDisplayed()) {
            await $(`>>>[title="Blink Convert"]`).click()
        }
    }
    let convertLeadModal = await $(`>>>enway-access-lead-convert c-convert-lead`)
    await convertLeadModal.waitForExist({ timeout: 5000 })
    await expect(convertLeadModal).toBeDisplayed()
})

As a result, the Convert Lead modal window has been opened.

In this phase, our autotest finished successfully.

As we can see, the main point of this check is not the process of creating a Lead. We need to operate with an object. But in this case, we spent some time developing the logic of finding specific locators for manual object creation. Moreover, the execution of this autotest will be prolonged due to these steps.

The full test for UI approach will look like:

import { getFrontdoorURLToOrg, getInstanceDomain } from '../utils/sfdx.js'

let domain, frontdoor

let lead = {
   salutation: 'Mr.',
   firstName: 'First Name',
   lastName: 'Last Name',
   company: 'ENWAY',
   website: 'https://enway.com/'
}

describe(' Create Lead object via UI and click Blink Covert button ', () => {
   before(async () => {
       domain = await getInstanceDomain()
       frontdoor = await getFrontdoorURLToOrg()
   })

   it('open Salesforce instance', async () => {
       await browser.url(frontdoor)
       await expect(browser).toHaveTitle('Lightning Experience | Salesforce')
   })

   it('open Lead tab', async () => {
       let leadTab = await $(`>>>one-app-nav-bar-item-root[data-id="Lead"]`)
       await leadTab.click()
       await expect(browser).toHaveTitleContaining('| Leads | Salesforce')
   })

   it('click New button and create new Lead object', async () => {
       let newButton = await $(`>>>[data-target-selection-name="sfdc:StandardButton.Lead.New"]`)
       await newButton.click()
       let modalWindow = await $(`>>>records-lwc-detail-panel`)
       await expect(await modalWindow).toBeDisplayed()
       let firstNameInput = await $(`>>>input[name="firstName"]`)
       let lastNameInput = await $(`>>>input[name="lastName"]`)
       let companyInput = await $(`>>>input[name="Company"]`)
       let websiteInput = await $(`>>>input[name="Website"]`)
       await firstNameInput.addValue(lead.firstName)
       await lastNameInput.addValue(lead.lastName)
       await companyInput.addValue(lead.company)
       await websiteInput.addValue(lead.website)
       let saveButton = await $(`>>>lightning-button [name="SaveEdit"]`)
       await saveButton.click()
       await expect(browser).toHaveTitle(`${lead.firstName} ${lead.lastName} | Lead | Salesforce`)
       let leadNameText = await $(`>>>[slot="primaryField"]`).getText()
       await expect(await leadNameText).toBe(`${lead.firstName} ${lead.lastName}`)
   })

   it('click Blink Convert button', async () => {
       let layoutButtonsBlock = await $(`>>>.slds-button-group-list`)
       await expect(layoutButtonsBlock).toBeDisplayed()
       let layoutButtonsShowMore = await layoutButtonsBlock.$(`>>>li.slds-button_last`)
       await layoutButtonsShowMore.waitForExist({ timeout: 5000 })
       if (await $(`>>>[title="Blink Convert"] lightning-button`).isDisplayed()) {
           await $(`>>>[title="Blink Convert"] lightning-button`).click()
       } else {
           await layoutButtonsShowMore.click()
           if (await $(`>>>[title="Blink Convert"]`).isDisplayed()) {
               await $(`>>>[title="Blink Convert"]`).click()
           }
       }
       let convertLeadModal = await $(`>>>enway-access-lead-convert c-convert-lead`)
       await convertLeadModal.waitForExist({ timeout: 5000 })
       await expect(convertLeadModal).toBeDisplayed()
   })
})

Salesforce Object Creation via Salesforce CLI

Now, let’s refactor this autotest using the Salesforce CLI tool. Firstly, we should log in to our org successfully. 

In the second step, we will create a Lead via Salesforce CLI. For that, use the following command:

sf data create record -s ${SOBJECTTYPE} -v "${VALUES}" --json

The result of this request will be a message with the creation status. If the object is created successfully, it will return an object Id.

Object creation via Salesforce CLI - Status Message

In our automated test it will look like:

it('create a lead via Salesforce CLI', async () => {
    let createdLead = await createRecord(
        'Lead',
        `FirstName='${lead.firstName}' LastName='${lead.lastName}' Company='${lead.company}' Website='${lead.website}'`
    )
    expect(createdLead.result.success).toBe(true)
    leadId = createdLead.result.id
})

In the next step, we won’t navigate to the Lead tab to open the created Lead. Instead, we will cheat a little bit and add the Id parameter to the browser URL to open the created object that way:

it('open created lead by URL', async () => {
    await browser.url(domain + leadId)
    await expect(browser).toHaveTitle(`${lead.firstName} ${lead.lastName} | Lead | Salesforce`)
    let leadNameText = await $(`>>>[slot="primaryField"]`).getText()
    await expect(await leadNameText).toBe(`${lead.firstName} ${lead.lastName}`)
})

Eventually, we can check the “Blink Convert” functionality. Like in the previous approach, let’s find and click it:

it('click Blink Convert button', async () => {
    let layoutButtonsBlock = await $(`>>>.slds-button-group-list`)
    await expect(layoutButtonsBlock).toBeDisplayed()
    let layoutButtonsShowMore = await layoutButtonsBlock.$(`>>>li.slds-button_last`)
    await layoutButtonsShowMore.waitForExist({ timeout: 5000 })
    if (await $(`>>>[title="Blink Convert"] lightning-button`).isDisplayed()) {
        await $(`>>>[title="Blink Convert"] lightning-button`).click()
    } else {
        await layoutButtonsShowMore.click()
        if (await $(`>>>[title="Blink Convert"]`).isDisplayed()) {
            await $(`>>>[title="Blink Convert"]`).click()
        }
    }
    let convertLeadModal = await $(`>>>enway-access-lead-convert c-convert-lead`)
    await convertLeadModal.waitForExist({ timeout: 5000 })
    await expect(convertLeadModal).toBeDisplayed()
})

Full test for CLI method will look like this:  

import { createRecord, getFrontdoorURLToOrg, getInstanceDomain } from '../utils/sfdx.js'

let domain, frontdoor, leadId

let lead = {
   salutation: 'Mr.',
   firstName: 'First Name',
   lastName: 'Last Name',
   company: 'ENWAY',
   website: 'https://enway.com/'
}

describe(' Check values in Lead object via CLI ', () => {
   before(async () => {
       domain = await getInstanceDomain()
       frontdoor = await getFrontdoorURLToOrg()
   })

   it('open Salesforce instance', async () => {
       await browser.url(frontdoor)
       await expect(browser).toHaveTitle('Lightning Experience | Salesforce')
   })

   it('create a lead via Salesforce CLI', async () => {
       let createdLead = await createRecord(
           'Lead',
           `FirstName='${lead.firstName}' LastName='${lead.lastName}' Company='${lead.company}' Website='${lead.website}'`
       )
       expect(createdLead.result.success).toBe(true)
       leadId = createdLead.result.id
   })

   it('open created lead by URL', async () => {
       await browser.url(domain + leadId)
       await expect(browser).toHaveTitle(`${lead.firstName} ${lead.lastName} | Lead | Salesforce`)
       let leadNameText = await $(`>>>[slot="primaryField"]`).getText()
       await expect(await leadNameText).toBe(`${lead.firstName} ${lead.lastName}`)
   })

   it('click Blink Convert button', async () => {
       let layoutButtonsBlock = await $(`>>>.slds-button-group-list`)
       await expect(layoutButtonsBlock).toBeDisplayed()
       let layoutButtonsShowMore = await layoutButtonsBlock.$(`>>>li.slds-button_last`)
       await layoutButtonsShowMore.waitForExist({ timeout: 5000 })
       if (await $(`>>>[title="Blink Convert"] lightning-button`).isDisplayed()) {
           await $(`>>>[title="Blink Convert"] lightning-button`).click()
       } else {
           await layoutButtonsShowMore.click()
           if (await $(`>>>[title="Blink Convert"]`).isDisplayed()) {
               await $(`>>>[title="Blink Convert"]`).click()
           }
       }
       let convertLeadModal = await $(`>>>enway-access-lead-convert c-convert-lead`)
       await convertLeadModal.waitForExist({ timeout: 5000 })
       await expect(convertLeadModal).toBeDisplayed()
   })
})

In these tests, you can see some utils methods imported from sfdx.js file. You can find them below:

import exec from 'executive'
import fs from 'fs'

/**
* This function creates a record in Salesforce.
* @param SOBJECTTYPE - The API name of the object you want to create.
* @param VALUES - The values to be inserted into the record.
* @returns The message with status.
*/
export async function createRecord(SOBJECTTYPE, VALUES) {
   await auth()
   let resp = await exec.quiet(`sf data create record -s ${SOBJECTTYPE} -v "${VALUES}" --json`)
   return await clearLogs(resp.stdout)
}

/**
* It writes the auth file to the apex directory and then stores the auth file in the sfdx auth store.
* @returns The auth function is returning the result of the exec.quiet function.
*/
export async function auth() {
   if (process.env.auth) {
       let file = { sfdxAuthUrl: process.env.auth }
       fs.writeFileSync(`./apex/authFile.json`, JSON.stringify(file))
   }
   return await exec.quiet(`sf org login sfdx-url --sfdx-url-file ./apex/authFile.json`)
}

/**
* It retrieves the domain of the current Salesforce instance.
* @returns the domain of the Salesforce instance.
*/
export async function getInstanceDomain() {
   await auth()
   let resp = await exec.quiet(`sf org display --json`)
   resp = await clearLogs(resp.stdout)
   let domain = resp.result.instanceUrl + '/'
   return domain
}

/**
* It generates the frontdoor URL to the organization after authenticating.
* @returns The URL of the frontdoor for the organization.
*/
export async function getFrontdoorURLToOrg() {
   await auth()
   let resp = await exec.quiet(`sf org open -r --json`)
   resp = await clearLogs(resp.stdout)
   let url = resp.result.url
   return url
}

/**
* It removes all the color codes from the string
* @param str - The string to be parsed
* @returns The result is a JSON object.
*/
export async function clearLogs(str) {
   let result = str
       .replace(/\x1B\[97m/g, '')
       .replace(/\x1B\[94m/g, '')
       .replace(/\x1B\[93m/g, '')
       .replace(/\x1B\[92m/g, '')
       .replace(/\x1B\[91m/g, '')
       .replace(/\x1B\[90m/g, '')
       .replace(/\x1B\[39m/g, '')
       .replace(/\x1B\[34m/g, '')
       .replace(/\x1B\[32m/g, '')
   return JSON.parse(result)
}

Final Thoughts

While employing the CLI tool accelerates your Salesforce testing, utilizing the UI approach provides a closer interaction with real users. In conclusion, I recommend flexibly combining both methods based on the requirements of your specific project.