Selenium Automated Testing using C# and TeamCity

Introduction

Our QA team have started creating Selenium scripts to automate browser functional testing. These allow us to automatically run through a set of actions on a website and flag up any issues.

Running Scripts Manually

You will need:

To create/open/run a script:

  1. Open Firefox
  2. Open Selenium (should be button on toolbar otherwise ctrl+alt+s or alt, Tools, Selenium IDE)
  3. Follow selenium documentation to record/playback scripts

Automating Scripts via Unit Tests

We can convert the scripts into C# unit tests and run them via TeamCity. This explains how to set this up. You will need:

  • First follow the above to create the test suite you wish to convert and ensure you can run scripts manually
  • Download Selenium Server from http://www.seleniumhq.org/download/ and store the .jar somewhere you can run it from. 
  • Run Selenium Server using Java (put this in a .bat file next to the .jar file and double click it:
    • “C:\Program Files\Java\jdk1.8.0_20\bin\java” -jar selenium-server-standalone-2.43.1.jar
  • Visual Studio 2013
  • Install NUnit from http://www.nunit.org/
  • NUnit Test Adapter (extension for VS 2013)
  • A .NET solution open to add the unit tests into

First prepare the solution for selenium unit tests:

  1. Add a new project (C# Class Library) suggest something like SiteName.SeleniumTests
  2. Right click the new project, Manage Nuget Packages, install the following:
    1. NUnit
    2. Selenium Remote Control (RC)
  3. Create a folder in which to place the unit tests (e.g. grouped like NewUserTests or just Tests)
  4. In Selenium IDE, choose File, Batch convert test cases, C#/Nunit/Remote Control
  5. Select your Tests folder as the destination folder
  6. Select all the test cases you wish to convert (html files) and they should be saved as C# files in the Tests folder
  7. In Visual Studio, show existing files, and Include in project all the generated .cs files
  8. Build (fix any compilation errors)
  9. Open Test > Windows > Test Explorer, this should show your tests (if not, rebuild)
  10. Close all Firefox windows (they can interfere with Selenium Server)
  11. Click Run All. Selenium Server should log the commands and launch Firefox to run the test.

To capture screenshots at the end of each test:

  1. Create a Screenshots folder in your unit test project
  2. In each .cs file, in Teardown method add the following line of code before selenium.Stop():
    1. selenium.CaptureEntirePageScreenshot(System.IO.Path.Combine(System.Environment.CurrentDirectory, @”..\..\Screenshots\” + this.GetType().Name + “.png”), “”);
  3. Run the test, screenshot should be saved into the Screenshots folder with same name as the test class.

Integration with TeamCity

To integrate into TeamCity, set up a build configuration to run the NUnit test with the following build steps:

  1. Compile selenium tests – Msbuild runner, point at Selenium.csproj file
  2. Run selenium tests – Nunit runner, run tests from (path to compiled DLL)

Set the Artifact paths setting on the build settings to point to the Screenshots folder to save the screenshots after each run.

To run via TeamCity the Selenium server must be running. You could start this manually same as above, hopefully this can be made to run automatically as a service but I’m not sure how.

Gotchas

Each test must be independent of any other as they may be run in any order, or perhaps only failed tests might be run. Also the server will restart the browser between each test so they can’t depend on the final state of the previous script (like they can in the IDE).

We’re going to try using New Relic Synthetics which has a feature for test automation – apparently you can upload a Selenium script and it can automatically run as and when, we have yet to try this out though!

Umbraco 7.2.1 Error when deployed via Web Deploy

When deploying latest Umbraco 7.2.1 to a test server via Web Deploy (through TeamCity) I got this error:

  • Could not load file or assembly ‘System.Web.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35’ or one of its dependencies. The system cannot find the file specified.

Turns out the following DLLs weren’t being deployed to the bin folder (these were part of various nuget packages as I installed the Umbraco nuget package):

  • System.Web.Http.dll
  • System.Web.Http.WebHost.dll
  • System.Net.Http.Formatting.dll

The fix for this was to find the reference in the website project and set copy local False then True. It’s missing a <private>True</private> flag in the project file.

If you get an issue like this I suggest you compare the bin folder vs your local site and see if anything’s missing.

Also while sorting this out I found an umbraco recommendation to upgrade to the latest version of MVC4 by running this command in the package console:

  • Update-Package Microsoft.AspNet.Mvc -Version 4.0.40804

Worth doing as well. After this I also had to set copy local False/True on System.Web.Mvc to get the latest MVC dll to copy in.

Respond to address selected JavaScript event with PostcodeAnywhere Capture+

Capture+ allows you to pop some code in your page and configure a JavaScript-driven address finder through your browser.

We wanted to hide the address fields until you select the address from the postcode lookup.

It doesn’t appear to let you customise the JavaScript in any way to allow this, however a query to their support turned up that you can respond to the event when a user selects an address with the following JavaScript:

<script type="text/javascript">
    capturePlus.listen("load", function(control) {
        //custom code
        control.listen("populate", function(address) {
            console.log("User selected: " + address.PostalCode);
			        });
    });
</script>

As this isn’t documented anywhere on their site I thought I would post it in case anyone else needs to know how to do this!

UPDATE: Actually it is documented at the end of http://www.postcodeanywhere.co.uk/support/articles/article/getting-started-with-captureplus

Restore NuGet Packages for Solution using TeamCity

So you’ve used NuGet packages into your solution and not checked in the packages folder to source control. Visual Studio will download the packages upon build, but TeamCity will not and you will end up with a build error such as:

This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is ..\packages\UmbracoCms.7.1.4\build\UmbracoCms.props.

But, how to enable NuGet Package Restore on TeamCity?

UPDATE: It seems this is as easy as in Visual Studio, right click the solution and Enable Nuget Package Restore for Solution. I’m sure I tried this before and it didn’t work, but it seems to now!

It’s quite easy. Just add a NuGet Installer build step (make sure to order it before the project build step):

 

All I specified is the NuGet version, path to solution file and Restore mode.

The first time you do this no default NuGet version will exist so you have to click NuGet Settings link and Fetch the latest version of NuGet.

Note that after this your build agents will disconnect to install the NuGet version.

Then your build should succeed! Awesome!

How to hide the Set associated content button in Sitecore

Sitecore Page Editor provides a Set associated content button in the floating toolbar around each component:

set-associated-content

This allows you to set the Data source for the component.

The selection can be restricted by Template or Location (in the Sitecore tree) by setting the page editor options on the component:

page-editor-options

If you have some components that require a data source and others that do not, it can be confusing for editors because the Set associated content button is always visible. The only way to see if it is intended to be used in a particular instance is by clicking it and seeing whether the developer has set the restrictions – if not then it allows you to pick any item from the whole site tree and you realise you probably aren’t meant to use it.

I thought it would be nice to only show the button if the Template restriction has been set, so the editor doesn’t try to use it when it isn’t intended.

To do this, I created a custom class to replace the built-in SetDatasource command:

using Sitecore.Data.Items;
using Sitecore.Shell.Applications.WebEdit.Commands;
using Sitecore.Shell.Framework.Commands;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Training.Utilities.BaseCore.Commands
{
    public class SetDatasourceIfTemplateSet : SetDatasource
    {
        public override CommandState QueryState(CommandContext context)
        {
            Sitecore.Data.ID renderingId;
            if (Sitecore.Data.ID.TryParse(context.Parameters["renderingId"], out renderingId))
            {
                Item renderingItem = Sitecore.Context.Database.GetItem(renderingId);
                if (string.IsNullOrEmpty(renderingItem["Datasource Template"]))
                {
                    return CommandState.Hidden;
                }
            }
            return base.QueryState(context);
        }
    }
}

Then in the /App_Config/Commands.config file, replace the webedit:setdatasource command type with our custom version:

<command name="webedit:setdatasource" type="Training.Utilities.BaseCore.Commands.SetDatasourceIfTemplateSet,Training.Utilities"/>

Then the button will only show up if a Datasource Template has been assigned.

How to get a spreadsheet of Sitecore template usage

I wanted to get an overview of all the templates in a Sitecore project along with how many times each has been used.

I thought there might be some marketplace module for doing this but couldn’t find one, nor could I find a suitable report in the ASR module.

So I wrote a little aspx script to write this out, hopefully it will be useful to someone:

<%@ Page Language="C#" AutoEventWireup="true" %><%

Response.ContentType = "text/csv";
var db = Sitecore.Data.Database.GetDatabase("master");
var templates = db.GetItem("/sitecore/templates/User Defined");
foreach (var template in templates.Axes.GetDescendants())
{
	if (template.TemplateName == "Template")
	{
		var usage = Sitecore.Globals.LinkDatabase.GetReferrerCount(template);

		if (template.Children["__Standard Values"] != null)
			usage--;

		Response.Write(template.ID + "," + template.Paths.Path + "," + usage + "," + Environment.NewLine);
	}
}

%>

Style up an sc:link field for Sitecore Page Editor

If you have a normal Link field which you render using an <sc:link /> control then you can select the link in a nice friendly way when editing through the Page Editor.

However if you have a custom css class to style your link then you might expect the link field to use that style in edit mode. Here’s an example link and the HTML we want it to render:

<a class="arrow-link" href="/">Read more</a>

However, when converted into an <sc:Link CssClass=”arrow-link” /> this is what Sitecore renders during edit mode, when you haven’t yet set a link:

Note that this doesn’t include an <a> tag at all. However, it does include the CSS class, albeit encoded into the sc_parameters attribute of the <code> element.

To make it styled-up using the same CSS class I added to the CSS an additional selector for the style:

So now as well as the .arrow-link class applying to actual .arrow-links, it also applies itself to Sitecore’s scTextWrapper span (which is where the [No text in field] is rendered). Now, before you fill it in, it looks like this:

Nice. This really helps if you have lots of similar-looking fields (e.g. Text, Links, etc) all below each other, as the editor can see which is meant for which. I would like to see if anyone has a nicer way of doing this by extending Sitecore, but I thought doing it in CSS would be a simple workaround.

Web Deploy Public Port 80 Warning

When installing web deploy DO NOT install the Remote Agent Service!

If you do, it will listen unsecured on public port 80 on the server, locked down only by username/password.

msdeploy

 

It listens at:

http://<site>/MsDeployAgentService

If it is running you can browse to that URL and it will ask for username/password. If this happens you should do a Change install and remove the remote agent service, or disable it!

Auto deploy Sitecore items using Unicorn and TeamCity

I recently discovered the Unicorn project by @kamsar, which implements an event handler to serialize Sitecore items to disk when they are modified, and a sync script which restores them on request.

UPDATE: This post is based on Unicorn 1 and 2. For details of the latest version (4) see the Unicorn github page. Also I have published another blog post about getting Unicorn items up to Azure web app using VSTS.

There were a few things which I had to figure out when setting this up to use for continuous integration in our environment, so I will outline the process.

Install and configure Unicorn

First, install the Unicorn nuget package.

Second, configure it to work on only the developer-owned items in your Sitecore tree. For these items we will consider the ‘master’ copy is that in source control, just like your codebase. The configuration is in /App_Config/Include/Serialization.config and I modified mine thus:

&lt;sitecore&gt;
 &lt;serialization&gt;
  &lt;default&gt;
   &lt;include database=&quot;master&quot; path=&quot;/sitecore/layout/Layouts/SITE&quot; /&gt;
   &lt;include database=&quot;master&quot; path=&quot;/sitecore/layout/Placeholder Settings/SITE&quot; /&gt;
   &lt;include database=&quot;master&quot; path=&quot;/sitecore/layout/Renderings/SITE&quot; /&gt;
   &lt;include database=&quot;master&quot; path=&quot;/sitecore/layout/Sublayouts/SITE&quot; /&gt;
   &lt;include database=&quot;master&quot; path=&quot;/sitecore/media library/System/SITE&quot; /&gt;
   &lt;include database=&quot;master&quot; path=&quot;/sitecore/templates/SITE&quot; /&gt;
  &lt;/default&gt;
 &lt;/serialization&gt;
&lt;/sitecore&gt;

Where SITE is a site-specific named folder containing all our site-specific items.

Next, serialize each of these Items using the Serialize Tree option in Sitecore’s Developer toolbar, and commit the serialized files from the $data/serialization folder.

From now on, when any of these items is modified in Sitecore, the corresponding file(s) will be modified and you can commit them along with code changes. These can be merged into your test / production branch along with other code.

Get the serialized files to be deployed

This step depends on your setup, but we set up our TeamCity CI to use WebDeploy to publish the Web Application Project to the server as per Troy Hunt’s article.

To get our items to be deployed required two things:

  1. Serialization folder must be under Website. I moved it to /App_Data and changed the path in Web.config
  2. An additional build step to sync the serialization folder:
C:\Program Files\IIS\Microsoft Web Deploy\msdeploy -verb:sync -source:contentPath=%teamcity.build.checkoutDir%\www\Website\App_Data\serialization -dest:contentPath=%env.DeployIisAppPath%/App_Data/serialization,wmsvc=https://%env.TargetServer%,userName=%env.PublishUsername%,password=%env.PublishPassword% -allowUntrusted

This ensures that when the build runs, new items will be added and old ones deleted to match what is in version control.

Get the items to be installed on build

This is done by the sync-database.aspx script included with Unicorn.

It will install the items if you are logged in as an Administrator, or if you include an Authenticate header matching a preconfigured token.

So add an app setting:

&lt;add key=&quot;DeploymentToolAuthToken&quot; value=&quot;{GUID OR TOKEN HERE}&quot;/&gt;

And then to make TeamCity call the script with the token I used wget (install for Windows here) and added a command line build step in TeamCity with the script:

C:\Program Files (x86)\GnuWin32\bin\wget %env.SyncScriptURL% -O - --header=Authenticate:%env.SyncScriptToken%

Then, if the build is successful, the script will run and Sitecore DB will be updated. In case it fails it should return non-200 and TeamCity flags this as an error.

We decided it would be ideal to publish the items as well as installing them into master db, so I added the following code into the sync-database.aspx.cs :

 /// &lt;summary&gt;
 /// Publish the preset folder as per docs in http://sdn.sitecore.net/upload/sitecore6/64/content_api_cookbook_sc64_and_later-usletter.pdf
 /// &lt;/summary&gt;
 /// &lt;param name=&quot;preset&quot;&gt;&lt;/param&gt;
 private static void PublishPreset(IncludeEntry preset)
 {
  if (preset.Database == &quot;master&quot;)
  {
   Sitecore.Data.Database master = Sitecore.Configuration.Factory.GetDatabase(&quot;master&quot;);
   Sitecore.Data.Database target = Sitecore.Configuration.Factory.GetDatabase(&quot;web&quot;);
   Sitecore.Data.Items.Item home = master.GetItem(preset.Path);
   Sitecore.Data.Database[] targetDatabases = { target };
   Sitecore.Globalization.Language[] languages = master.Languages;
   bool deep = true;
   bool compareRevisions = true;
   Sitecore.Publishing.PublishManager.PublishItem(home, targetDatabases, languages, deep, compareRevisions);
  }
 }

I call this code from within ProcessPreset:

new SerializationLoader().LoadTree(
 new AdvancedLoadOptions(preset)
 {
 Progress = progress,
 ForceUpdate = false,
 DeleteOrphans = true
 });

PublishPreset(preset);

Now my items are installed and published on deploy.

Strongly typed repeaters in ASP.NET 4.5 (Sitecore 7)

If you use Web Forms then this might be helpful.

In a Repeater (and other data binding container controls) instead of something like this:

<%# ((Sitecore.Data.Items.Item)Container.DataItem)["Field"] %>

You can now do this:

<%# Item["Field"] %>

If you include this Repeater attribute:

ItemType="Sitecore.Data.Items.Item"

We can do this with Sitecore 7 J

For more information http://stackoverflow.com/questions/937244/strong-typed-container-in-webforms