This lesson is aimed at developers and QA engineers looking to enhance their testing strategies for web applications that interact with Salesforce. Let’s break down the initial setup and preparation steps for our test environment, showcasing the use of Playwright alongside Salesforce’s UI for a comprehensive testing workflow.

Setting the Stage for Playwright with Salesforce

Before diving into the code, it’s crucial to understand the tools and libraries we’re working with:

  • Playwright: A Node.js library to automate Chromium, Firefox, and WebKit with a single API. It enables cross-browser testing and offers features for web interactions and monitoring.
  • JWTToken authentication: Skipps the UI login process and is the best way to access Salesforce with UI automation for now, even better then TOTP protocol .

Our example demonstrates the preparation steps necessary to test accounts functionality within a Salesforce application. Let’s dissect the code snippet provided:

Step 1: Create a Salesforce Acccount Necessary Libraries and Pages accountsjwt.js file which you can find in this example repository

import { test, expect, chromium } from '@playwright/test';
import Setup from "../pages/setup.page.js";
import Overview from "../pages/overview.page.js";
import Account from "../pages/accounts.page.js";
import { fill_In_Combo } from "../functions/functions.js";
import fs from "fs-extra";
import { getSalesforceAccessToken } from '../../salesforceAuth.js';

Here, we import the essentials:

  • Playwright’s test, expect, and chromium for browser automation.
  • Page objects lik , Setup, Overview, and Account to encapsulate the actions and elements of each page.
  • Helper functions and the fs-extra package for file operations.
  • A custom function getSalesforceAccessToken to authenticate with Salesforce.

Step 2: Setup and Authentication

let jsonData = "";
let loginPage, setup, overview, account, browser, context, page;
let salesforceApiCredentials;

test.describe("Testing the accounts functionality", () => {
  test.beforeAll(async () => {
    // Obtain Salesforce API credentials
    salesforceApiCredentials = await getSalesforceAccessToken();
    if (!salesforceApiCredentials || !salesforceApiCredentials.access_token || !salesforceApiCredentials.instance_url) {
      throw new Error('Did not receive valid Salesforce credentials for API tests.');
    }
    console.log('Salesforce API credentials obtained for Playwright tests.');

    // Load test data
    jsonData = await fs.readJson("./tests/testdata/testdata-accounts.json");
    browser = await chromium.launch();

    // Create a new browser context
    context = await browser.newContext({
      viewport: { width: 1920, height: 1080 }
    });
    page = await context.newPage();

    // Authenticate using the obtained Salesforce access token
    await context.addCookies([{
      name: 'sid',
      value: salesforceApiCredentials.access_token,
      domain: new URL(salesforceApiCredentials.instance_url).hostname,
      path: '/',
      httpOnly: true,
      secure: true
    }]);
  • Obtaining Salesforce Credentials: We start by acquiring Salesforce API credentials necessary for authentication. This process ensures that our automated tests can interact with Salesforce as an authenticated user.
  • Preparing Test Data: Load JSON data (testdata-accounts.json) that will be used throughout the tests to interact with account functionalities.
  • Launching the Browser: Using Playwright’s chromium.launch(), a new browser instance is initiated.
  • Creating Browser Context and Page: A new browser context is created with a specified viewport size, followed by opening a new page within this context.
  • Authentication: We set a cookie containing the Salesforce access token, effectively authenticating our session.

Step 3: Navigating to Salesforce

    // Navigate to the Salesforce instance URL
    console.log('Navigating to Salesforce instance...');
    await page.goto(salesforceApiCredentials.instance_url, { waitUntil: 'networkidle' });

Finally, we navigate to the Salesforce instance using the credentials obtained earlier. This step marks the beginning of our tests, as we’re now in the Salesforce environment, ready to execute our accounts functionality tests.

Filling in Form Inputs

The initial part of our automation script deals with filling in various form inputs. These inputs include combo boxes (dropdown menus) for ratings, ownership types, customer priority levels, account activity statuses, SLA (Service Level Agreement) types, and upsell opportunities. To interact with these elements, the script employs a function fill_In_Combo, which likely selects the appropriate option based on the label of the combo box and the desired value.

await fill_In_Combo(page, jsonData.accounts.input.labelOfRating, jsonData.accounts.input.typeOfRating);
await fill_In_Combo(page, jsonData.accounts.input.labelOfOwnership, jsonData.accounts.input.typeOfOwnership);

This approach demonstrates how to abstract the process of filling in form elements into reusable functions, thereby making the code cleaner and more maintainable.

Handling Address Information

Next, the script fills in address information for both billing and shipping addresses. It uses a method fill_In_AddressInformation on an account object, passing in address details such as the address type (billing or shipping), street address, province, and country.

await account.fill_In_AddressInformation(
  jsonData.accounts.billingAddress.billingAddress,
  jsonData.accounts.billingAddress.address,
  jsonData.accounts.billingAddress.province,
  jsonData.accounts.billingAddress.country
);

This step illustrates how to handle grouped form inputs that share a common context, in this case, address information. Grouping these inputs into a single function call simplifies the code and enhances readability.

Additional Information and Description

The script further demonstrates filling in additional account information and a description for the new account. These actions likely involve interacting with text fields or possibly more combo boxes.

await account.fill_In_additionalInformation(
  jsonData.accounts.input.numberOfLocations,
  jsonData.accounts.input.slaSerialNumber
);

await account.fill_In_A_Description(jsonData.accounts.input.accountsDescription);

This part of the script shows the importance of handling various types of inputs, from numeric fields to large text areas, each of which may require different strategies for data entry.

Handling Conditional UI Elements

An interesting aspect of this script is its handling of conditional UI elements, specifically a warning dialog that may appear after attempting to save the new account:

const similarRecordWarning = page.locator('[title="Close error dialog"]');
if (await similarRecordWarning.isVisible()) {
  await similarRecordWarning.click();
  await account.click_SaveButton();
}

This code snippet demonstrates a common scenario in web application testing: dealing with unexpected or conditional UI elements. The script checks if a warning dialog is visible and, if so, dismisses the dialog before attempting to save again. This is a crucial step in ensuring the robustness of the test, as it can handle variations in the application’s behavior. If you want to use it you can find the repository here

Playwright Salesforce Automation Guide

Conclusion

Automating web application testing involves more than just straightforward interactions with static elements. It requires handling dynamic and conditional elements, abstracting repetitive tasks into functions for better maintainability, and ensuring the test can adapt to different scenarios. The example provided illustrates these principles in action, offering a glimpse into the strategies used by testers to automate complex web application interactions effectively.