Wilson Mar bio photo

Wilson Mar


Calendar YouTube Github


Enable C# Microsoft developers to use Selenium test infrastructures on Alt-macOS

US (English)   Norsk (Norwegian)   Español (Spanish)   Français (French)   Deutsch (German)   Italiano   Português   Estonian   اَلْعَرَبِيَّةُ (Egypt Arabic)   Napali   中文 (简体) Chinese (Simplified)   日本語 Japanese   한국어 Korean


Here is a hands-on tutorial to learn Selenium using the C# language edited in Visual Studio on MacOS. This an “immersion” approach as if you just got hired and are looking at a fully developed set of code to modify.

A lot of thought has gone into sequencing topics here so you learn easier, in less time.

The pre-requisite to this is the “start from scrach” approach of courses such as the one on Udemy from UltimateQA filmed 2015 by Nikolay Advolodkin (@Nikolay_A00, Facebook) and Dr. Tiffany Ford (rhysma@live.com) who teaches C#. quizzes.

Why this?

Microsoft’s VSTS (Visual Studio Team Services) costs several thousand dollars while Selenium is free (open source).

Run several Selenium instances in parallel on publicly available swarm facilities such as SauceLabs, BrowserStack, Rainforest.qa, https://crossbrowsertesting.com, and Selenium Grid in-house.

Include the Neotys API so that when Selenium is run, NeoLoad automatically updates “user paths” (scripts) for load testing.


Install Visual Studio IDE

The Community Edition of Visual Studio IDE can be used.

If you already have Visual Studio IDE installed, go here.

Mac install

  1. Use https://aka.ms/vsmac to https://www.visualstudio.com/vs/visual-studio-mac/ VisualStudioInstaller.dmg (25.3 MB)

    This is analogous to downloading Visual Studio for Windows at https://www.visualstudio.com/downloads

  2. In Downloads folder, invoke the installer.
  3. Uncheck the Android, iOS, macOS platforms, for 774 MB download, which takes a long time.

    While you wait, look at the documentation at https://docs.microsoft.com/en-us/visualstudio/mac/

    This IDE replaced Xamarin Studio as a full-featured IDE on Mac. But its Developer Center” still references Xamarin.

    I kept getting an System.AggregateException”, “Xamarin.iOS needs to be installed”.

    So I had to download VisualStudioForMac- (290 MB). and then drag and drop the Visual Studio for Mac icon to the Applications folder.

  4. Sign in and Activate license for Professional/Enterprise features:



    Problems reported are at: https://developercommunity.visualstudio.com/spaces/41/index.html

    To report a problem with Visual Studio for Mac: https://developercommunity.visualstudio.com/content/problem/post.html?space=41&inRegister=true

Windows install

Get Sample Selenium Code

  1. Fork the excellent sample code at:


  2. Assuming you have Git client installed, download the repo from your account. For example:

    git clone https://github.com/wilsonmar-jetbloom/Onty.SeleniumTest.Webmail.git

  3. Use MacOS Finder or Windows Explorer to view the folder.
  4. Delete the .vs folder so that the solution is not opened using them.

    NOTE: From the root is a .vs folder which leads to a binary file .suo. This file contains user preference configurations specific to each machine. So although it is recreated automatically by Visual Studio, recreation resets metadata such as whether the project is loaded/unloaded at any given time. So its name should be specified in .gitignore and not pushed to GitHub.

    Install app.config Developer Pack

  5. Open a text editor and navigate into folder “Onty.SeleniumTest.Webmail”.

  6. Open file app.config to see:

    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2"/>
  7. Get it.

    On Windows:

    Click “Download” at this page


    Microsoft .NET 4.62 Developer Pack



    On Mac:

    https://www.microsoft.com/net/core#macos Click “Download .NET Core SDK” for file: dotnet-sdk-2.0.0-osx-gs-x64.pkg (133 MB)

    NOTE: .NET Core is a newer approach than .NET Framework for server applications. .NET Core provides support for cross-platform development (Windows, Linux, and macOS) within Docker containers.

    But .NET Framework libraries are still used for apps using third-party .NET libraries or NuGet packages not available for .NET Core.

    http://dot.net provides a bash console

Install WebDrivers

Install WebDrivers on Windows

In app.config:

  <setting name="PathFirefox" serializeAs="String">
      <value>C:\Program Files\Mozilla Firefox\firefox.exe</value>
  <setting name="WebDriverType" serializeAs="String">


Processing of this results in WebDriver executables in the project’s root folder:

  • WebDriver.dll
  • WebDriver.Support.dll
  • nunit.framework.dll
  • chromedriver.exe
  • geckodriver.exe (for Mozilla Firefox)
  • IEDriverServer.exe
  • phantomjs.exe

Install WebDrivers on MacOS

.dll and .exe are for Windows only and don’t work on a Mac.

So we need to:

  1. Use https://www.npmjs.com/package/webdriver-manager

    npm install -g webdriver-manager

  2. download the selenium server jar and chromedriver binary:

    webdriver-manager update

    The response:

    /Users/mac/.npm-packages/bin/webdriver-manager -> /Users/mac/.npm-packages/lib/node_modules/webdriver-manager/bin/webdriver-manager
           + webdriver-manager@12.0.6
    added 96 packages in 26.426s
  3. Start Selenium Server attached to foreground process:

    webdriver-manager start

    Alternately, start in background:

    webdriver-manager start --detach

    The response:

    webdriver-manager: using global installed version 12.0.6
    [21:04:30] I/file_manager - creating folder /Users/mac/.npm-packages/lib/node_modules/webdriver-manager/selenium
    [21:05:04] I/update - chromedriver: unzipping chromedriver_2.32.zip
    [21:05:04] I/update - chromedriver: setting permissions to 0755 for /Users/mac/.npm-packages/lib/node_modules/webdriver-manager/selenium/chromedriver_2.32
    [21:05:47] I/update - geckodriver: unzipping geckodriver-v0.18.0.tar.gz
    [21:05:47] I/update - geckodriver: setting permissions to 0755 for /Users/mac/.npm-packages/lib/node_modules/webdriver-manager/selenium/geckodriver-v0.18.0
  4. Open browser to http://localhost:4444/wd/hub

  5. Stop Selenium Server if opened in background process:

    webdriver-manager stop

Install WebDrivers On a Mac

  1. TODO: On a Mac, change “C:\Program Files\Mozilla Firefox\firefox.exe” to ???

    brew install selenium-server-standalone

  2. Look into what is installed:

    cat $(which selenium-server)

    Which yields:

    exec java  -jar /usr/local/Cellar/selenium-server-standalone/3.5.3/libexec/selenium-server-standalone-3.5.3.jar "$@"
  3. The .jar contains a .plist file which defines the default port for the equivalent of:

    selenium-server -port 4444

    The response: Selenium Server is up and running

    For more options:

    selenium-server -help

    Widen the window to see without wrapping:

    Usage: <main class> [options]
     --version, -version
        Displays the version and exits.
        Default: false
        <Integer> in seconds : number of seconds a browser session is allowed to
        hang while a WebDriver command is running (example: driver.get(url)). If the
        timeout is reached while a WebDriver command is still processing, the session
        will quit. Minimum value is 60. An unspecified, zero, or negative value means
        wait indefinitely.
        Default: 0
        <Boolean> : enables LogLevel.FINE.
        Default: false
        <Boolean>: Whether or not to use the experimental passthrough mode.
        Defaults to true.
        Default: true
     -jettyThreads, -jettyMaxThreads
        <Integer> : max number of threads for Jetty. An unspecified, zero, or
        negative value means the Jetty default value (200) will be used.
        <String> filename : the filename to use for logging. If omitted, will log
        to STDOUT
        <Integer> : the port number the server will use.
        Default: 4444
        <String> options are [hub], [node], or [standalone].
        Default: standalone
     -timeout, -sessionTimeout
        <Integer> in seconds : Specifies the timeout before the server
        automatically kills a session that hasn't had any activity in the last X seconds. The
        test slot will then be released for another test to use. This is typically
        used to take care of client crashes. For grid hub/node roles, cleanUpCycle
        must also be set.
        Default: 1800

Other properties in app.config

NOTE: Having strings such as PageLoadDelay in this file makes the solution more flexible than hard-coding into C# code. TODO: Additional variables include:

  • PageLoadTimeout = 60,
  • ScriptTimeout = 60,
  • ElementsWaitTimeout = 60

  1. Navigate into file ….csproj

    The …..csproj.user ???

In Visual Studio


  1. Within Windows Explorer or macOS Finder, double-click on the .sln solution file to open it within Visual Studio.

    PROTIP: Inside the .sln file, the “Visual Studio 14” is marketed by Microsoft as “Visual Studio 2015”.

    Restore NuGet Package Dependencies

  2. To download component dependencies in appropriate locations, in the Solution Explorer tool window, right-click on References. On Windows: click Restore NuGet Packages

    selenium-cs-restore nuget packages-320x194


    NOTE: This is similar to running Maven to process its pom.xml file. But Visual Studio uses the packages.config.

  3. View file package.config containing:

      <package id="Chromium.ChromeDriver" version="2.27" targetFramework="net46" />
      <package id="NUnit" version="3.6.0" targetFramework="net46" />
      <package id="NUnit3TestAdapter" version="3.7.0" targetFramework="net46" />
      <package id="Selenium.Support" version="3.0.1" targetFramework="net46" />
      <package id="Selenium.WebDriver" version="3.0.1" targetFramework="net46" />
      <package id="Selenium.WebDriver.PhantomJS" version="" targetFramework="net46" />
      <package id="WebDriver.GeckoDriver" version="0.13.0" targetFramework="net46" />
      <package id="WebDriverIEDriver" version="" targetFramework="net46" />

    The id of each packages specifies what is downloaded from Microsoft’s NuGet Gallery, such as: https://www.nuget.org/packages/NUnit3TestAdapter


    Project Docs Notes

  4. Open Docs/notes.txt to add txt about the effort.

    PROTIP: Add new text at the top. Begin each entry with a date such as “2017-09-23”.

  5. Click “Step Into” to run the file one line of code at a time.

    Properties of Domain

  6. Navigate into the Properties folder.
  7. Notice file AssemblyInfo.cs says

    "This package contains a set of automated functional tests (via Selenium) for a Simple Webmail System."

    NOTE: There are various Designer.cs files which contain the declaration and initialization of UI controls and form layouts. File Settings.Designer.cs is generated by Visual Studio based on information in file settings.settings using the settings designer updated upon changes to the Project + Settings tab. To force re-generation, delete the Settings.designer.cs file, then right-click on the settings.settings file and select “Run custom tool”.

  8. Notice file Settings.settings defines the app running in the Heroku cloud:

  9. Click to open the sample app running on the Heroku cloud:


    (But you can set up the webmain app in your own server.)

    Common PageObjects and annotations

  10. Right-click to View Page Source to see the HTML, containing HTML such as this:

      <a id="nav-Login" href="/accounts/login">login</a>
      <a id="nav-Signup" href="/accounts/signup">create an account</a>.
  11. Search for an attribute id “nav-Login” and open file CommonPageElements.cs to see it referenced:

    [FindsBy( How = How.CssSelector, Using = "a#nav-Login" )]
     protected IWebElement LinkLogin { get; set; }

    PROTIP: The “FindsBy” with square brackets are compiler annotations used to reducing coding overhead. It is from the OpenQA.Selenium.Support.PageObjects.FindsByAttribute WebDriver which “Initializes a new instance of the FindsByAttribute class”.

    The LinkLogin web element is defined by a getter and setter.

    Get CSS

  12. Open a new browser window and construct the URL to view the CSS file. Combine the URL:


    and concatenate from the HTML:


    The response is minified to remove spaces and line breaks not necessary to the computer.

  13. PROTIP: Copy all the CSS and paste it into a new window at:


    Copy and paste the output to a text file so you can use your favorite editor to search in it.

    Domain objects

  14. Navigate up and into the Domain folder that defines objects in the app’s domain.
  15. File User.cs
  16. File Message.cs
  17. File Folder.cs

  18. View file ATest.cs which defines Setup and Teardown for all tests in each run.

    NOTE: Each .cs (C#) file within this folder specifies the folder name in its namespace:

    namespace Onty.SeleniumTest.Webmail.Tests

    [TestFixture] is a compiler annotation.


    To see where this is defined:


  19. Navigate up and into Utils folder.

    Files here define utility functions:

  20. Open WebDriverFactory.cs. The GetWebDriver function invokes depending on what value is defined for the wdt variable.

  21. Open others:

    • Rnd.cs for a rnd() random function based on a millisecond.
    • ScreenShotUtil.cs for the TakeScreenshot() function.
    • StringUtil.cs for IntToBase26() and MakeRandomString().

    SignUp (several users)

    File TestData.cs adds new users with hard-coded names and passwords.


    Within PageObjects, file AccountsSignupPage.cs


  22. Navigate into the Tests folder.

    BLAH: Name tests using action verbs such as: ???

    • Landing
    • File Tests_General.cs has Test_General_Menu() that logs in and checks the menu.
    • Tests_Login.cs has Test_Login_Invalid() and Test_Login_Valid()
    • Tests_Mailbox.cs has Test_Mailbox_Home(), Test_Mailbox_CreateFolder and Test_Mailbox_SendMessage()
    • Tests_NotLoggedIn.cs has Test_NotLoggedIn_Home() to detect when “not-logged-in message is not displayed”.

App PageObjects

Test code reference objects defined in PageObjects.

The Common\APage.cs file defines the base class/

The CommonPageElements.cs file overrides APage:

public class CommonPageElements : APage

Other PageObjects reference CommonPageElements:

public class AccountsHomePage : CommonPageElements

### Build, Run, Troubleshoot

  1. Build the solution.
  2. Open Test Explorer tool window in Visual Studio,
  3. Click Run All or Build icon.

    Alternately, you can click on a single [TestMethod] and right-click to select “Run Tests” or hold down command/ctrl+R,T.

    If it doesn’t run, we have a debugging session.

    See debugging tips

Add your own

Here is a crucial aspect of this tutorial.

Add new field

Change text validated

Add new form

Re-use for other apps

The structure of application code provides a base for re-use to test other applications:

  • Home
  • Login
  • Password
  • Signup

Here is my plan to generate this set of files automatically.

Many functions are “boilerplate” that are the same for all applications.

PROTIP: The advantage of code generation is that tests would be based not just on what elements appears in the app, but also on what should be there based on design specs.

Moustache Templating

A templating program is used to replace static text with variables inserted in files, such as this, which is in most files:

  `namespace Onty.SeleniumTest.Webmail.PageObjects`

  `namespace Onty.SeleniumTest.\{\{AppShortName}}.PageObjects`

For more complex replacements:

  `using Onty.SeleniumTest.Webmail.\{\{FolderAbove}};`

  `public class \{\{ThisFolderName}} : CommonPageElements`

Yeoman code generator

We use Yeoman for adding logic to generate code. Just like JHipster does.

See https://docs.microsoft.com/en-us/aspnet/core/client-side/yeoman

Yeoman is a project scaffolding system for creating many kinds of applications.

The Yeoman generator for ASP.NET Core contains a variety of project templates for starting a new web, MVC, or console application.

To install Yeoman, use Node:

npm install -g yo bower

Alternatively, https://leaptest.com/pages/selenium-testing


Selenium Learning Resources

http://courses.ultimateqa.com/courses/synchronization-techniques Selenium Webdriver Synchronization Techniques Course</a>

http://courses.ultimateqa.com/courses/parallel-testing-tutorial Introduction to Sauce Labs and Browser Stack</a> free tutorial