Vintage toy robot

Automated Testing for the Sitecore Admin Console

Jun 16, 2020
Prasanth Nittala

As automation takes on a larger role in companies, more and more organizations are looking to automate testing, including UI testing. Selenium is considered the go-to library for UI testing. At Oshyn, we’ve built the “Oshyn Selenium Framework” around Selenium which helps us test pages easily and efficiently.

Once this framework was in place, we decided to build another framework, the “Oshyn Sitecore UI Framework”, that allows users to easily log in and navigate through the Sitecore console pages and perform actions in an automated way. For example, log in to Sitecore console, go to content editor, select node, and publish items selecting various options.

Oshyn Framework Dependencies

The framework was built such that it can log in to different versions of Sitecore (with or without identity server) and perform the operations. We have followed the Page Object Pattern for representing the individual pages such as LoginPage, LaunchPadPage, ContentEditorPage, XpAnalyticsPage, and XpProfilePage and abstracted the operations performed on those pages. The kind of operations exposed by the pages are as follows:


Page Operations

LoginPage

  • Login(username, password)

LaunchPadPage

  • IsContentEditorAvailable()
  • GetContentEditor()
  • IsExperieneAnalyticsAvailable()
  • GetExperienceAnalytics()
  • IsExperienceProfile()
  • GetExperienceProfile()

These are just some of the API’s.

LaunchPadPage

  • GetSitecoreItem()
  • GetItemId(WebElement webelemnt)
  • IsElementExpanded(IWebElement element, int? timeoutSeconds = null);
  • SelectElement(string path)
  • SelectElement(IWebElement element, string childElementName, bool expandElement = true, int? timeoutSeconds = null)
  • SelectTab(IWebElement element, TabType tabName, int? timeoutSeconds = null);
  • PublishItem(IWebElement element, PublishOptions options, bool selectPublishTab = true, int? timeoutSeconds = null);
  • ClickXPathElement(IWebElement element, string xpath, int? timeoutSeconds = null);
  • ExpandElement(IWebElement element, int? browsingDelayMilliseconds = null);
  • CollapseElement(IWebElement element, int? browsingDelayMilliseconds = null);

With these operations in place, a tester can write test scripts using this API easily without needing to worry about the underlying layer, as to how the operation is performed. A tester can write his/her own operations with the help of the API’s provided above to automate any operation behind the Sitecore Admin console. As an example, the publish operation and its implementation is shown here below corresponding to the “Oshyn Sitecore UI Framework” and “Testing Project” layers:

PublishItem in Oshyn Sitecore UI Framework
public bool PublishItem(IWebElement element, PublishOptions options, bool selectPublishTab = true, int? timeoutSeconds = null)
{
    element = element ?? throw new ArgumentNullException(nameof(element));
    options = options ?? throw new ArgumentNullException(nameof(options));
    timeoutSeconds = timeoutSeconds ?? Settings.DefaultTimeoutSeconds;
    var itemPublished = false;
    if (selectPublishTab) {
        SelectTab(element, TabType.Publish, timeoutSeconds.Value);
    }
    try {
        StartPublishModal(timeoutSeconds.Value);
        SelectPublishOptions(options, timeoutSeconds.Value);       
        Publish(options);
        itemPublished = true;
    } catch (Exception ex) {
        SetLastException(ex);
    }
    return itemPublished;
}


#region Private Methods
 
/// <summary>
/// Click "Publish Item" in Publish chunk to invoke Publish modal
/// </summary>
/// <param name="timeoutSeconds"></param>
private void StartPublishModal(int timeoutSeconds) {
    TryJSClick("publishitem", timeoutSeconds);
    Driver.SwitchTo().Frame("jqueryModalDialogsFrame");
    Driver.SwitchTo().Frame("scContentIframeId0");
}
 
/// <summary>
/// Set the Publish Options in modal based on the PublishOptions object
/// </summary>
/// <param name="options"></param>
/// <param name="timeoutSeconds"></param>
private void SelectPublishOptions(PublishOptions options, int timeoutSeconds) {
    SelectPublishType(options, timeoutSeconds);
    ChosePublishSubItems(options, timeoutSeconds);
    ChosePublishRelatedItems(options, timeoutSeconds);
}
/// <summary>
/// Set the PublishType to Republish or Smart Publish
/// </summary>
/// <param name="options"></param>
/// <param name="timeoutSeconds"></param>
private void SelectPublishType(PublishOptions options, int timeoutSeconds)  
{
    TryClick(options.PublishType == PublishType.Republish ? "republish" : "smartpublish", timeoutSeconds);
}
 
/// <summary>
/// Set the Publish sub items checkbox based on options
/// </summary>
/// <param name="options"></param>
/// <param name="timeoutSeconds"></param>
private void ChosePublishSubItems(PublishOptions options, int timeoutSeconds) {
    SetCheckBoxValue("publishsubitems", options.PublishSubItems, timeoutSeconds);
}
 
/// <summary>
/// Set the Publish related items checkbox based on options
/// </summary>
/// <param name="options"></param>
/// <param name="timeoutSeconds"></param>
private void ChosePublishRelatedItems(PublishOptions options, int timeoutSeconds) {
    SetCheckBoxValue("publishrelateditems", options.PublishRelated, timeoutSeconds);
}
 
/// <summary>
/// perform the publish operation based on the options
/// </summary>
/// <param name="options"></param>
private void Publish(PublishOptions options) {
    TryClick("publishbtn");
    if (options.PublishType == PublishType.Republish || options.PublishRelated || options.PublishSubItems) {
        ConfirmPublish();
    }
    WaitForFinishingPublish();
    TryClick("closebtn");
    Driver.SwitchTo().ParentFrame();
    Driver.SwitchTo().ParentFrame();
}
 
/// <summary>
/// confirm OK to additional modals during publish operation
/// </summary>
private void ConfirmPublish() {
    Driver.SwitchTo().ParentFrame();
    Driver.SwitchTo().Frame("scContentIframeId1");
    TryClick("confirmpublishokbtn");
    Driver.SwitchTo().ParentFrame();
    Driver.SwitchTo().Frame("scContentIframeId0");
}
/// <summary>
/// wait for publish operation to finish
/// </summary>
private void WaitForFinishingPublish() {
    var element = GetElementFromControlKey("finishedpublish");
    var isDisplayed = element.GetCssValue("display");
    while (isDisplayed != null && isDisplayed.Equals("none")) {
        Thread.Sleep(Settings.BrowsingDelayMilliseconds);
        isDisplayed = element.GetCssValue("display");
    }
}
PublishItem In TestProject

[Test]
public void PublishItem_RePublishWithSubItemsAndWithRelatedItems() {
    var op = new PublishOptions {
        PublishSubItems = true,
        PublishRelated = true,
        PublishType = PublishType.Republish
    };
    var published = PublishItem(op);
    Assert.True(published);
}

private bool PublishItem(PublishOptions options) {
_launchPadPage = SitecoreConsole.Login(Settings.SitecoreConsoleUsername, Settings.SitecoreConsolePassword);
    _cePage = _launchPadPage.GetContentEditor();
    var home = _cePage.SelectElement("/sitecore/Content/Home");
    return _cePage.PublishItem(home, options);
}

In the video below, I walk through using our Sitecore Console Automation application to open a browser, log in to the Sitecore console, and perform a publish operation by selecting different options on the publish wizard.