Run the sample web app visual test

Step 1: Setup environment

Requirements

  • .NET 9.0
  • NUnit framework
  • Appium client
  • Access key
    • You can generate an Access key using the following instruction – Access key
  • Billing unit
    • The billing unit is your team’s unique identifier, or just the word “personal” in the case of an individual account.
      More information can be found here.

Step 2: Add the interaction with visual testing API

After setup up the environment, you need to add the interaction with the visual testing API:

using NUnit.Framework;
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Drawing;

namespace AppiumTests
{

    public class VisualBuildInputData
    {
        [JsonPropertyName("name")]
        public string Name { get; set; }

        [JsonPropertyName("project")]
        public string Project { get; set; }

        [JsonPropertyName("branch")]
        public string Branch { get; set; }
    }

    public class VisualSnapshotInputData
    {
        [JsonPropertyName("name")]
        public string Name { get; set; }

        [JsonPropertyName("buildId")]
        public string BuildId { get; set; }

        [JsonPropertyName("image")]
        public string Image { get; set; } // Path to the image file

        [JsonPropertyName("testName")]
        public string TestName { get; set; }

        [JsonPropertyName("suiteName")]
        public string SuiteName { get; set; }

        [JsonPropertyName("device")]
        public string Device { get; set; }
    }

    public class VisualBuildData
    {
        [JsonPropertyName("id")]
        public string Id { get; set; }

        [JsonPropertyName("name")]
        public string Name { get; set; }

        [JsonPropertyName("project")]
        public string Project { get; set; }

        [JsonPropertyName("branch")]
        public string Branch { get; set; }

        [JsonPropertyName("status")]
        public string Status { get; set; }
    }

    public class VisualSnapshotData
    {
        [JsonPropertyName("id")]
        public string Id { get; set; }

        [JsonPropertyName("name")]
        public string Name { get; set; }

        [JsonPropertyName("buildId")]
        public string BuildId { get; set; }

        [JsonPropertyName("testName")]
        public string TestName { get; set; }

        [JsonPropertyName("suiteName")]
        public string SuiteName { get; set; }

        [JsonPropertyName("browser")]
        public string Browser { get; set; }
    }



    public class VisualTestingAPI
    {
        private readonly HttpClient _httpClient;

        public VisualTestingAPI(string baseUrl, string apiKey)
        {
            _httpClient = new HttpClient
            {
                BaseAddress = new Uri(baseUrl)
            };
            _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);;
            _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        }

        public VisualBuildData CreateBuild(VisualBuildInputData inputData)
        {
            var jsonContent = JsonSerializer.Serialize(inputData);
            var stringContent = new StringContent(jsonContent, System.Text.Encoding.UTF8, "application/json");

            var response = _httpClient.PostAsync("builds", stringContent).Result; // Wait for response synchronously
            response.EnsureSuccessStatusCode();

            var responseContent = response.Content.ReadAsStringAsync().Result;
            return JsonSerializer.Deserialize<VisualBuildData>(responseContent);

        }

        public void FinishBuild(string buildId)
        {
            var response = _httpClient.PostAsync($"builds/{buildId}/finish", null).Result; // Wait synchronously
            response.EnsureSuccessStatusCode();

            Console.WriteLine("Build finished successfully");
        }

        public VisualSnapshotData SubmitSnapshot(VisualSnapshotInputData inputData)
        {
            // Prepare Multipart/Form-Data content
            var formContent = new MultipartFormDataContent
            {
                { new StringContent(inputData.Name), "name" },
                { new StringContent(inputData.TestName), "testName" },
                { new StringContent(inputData.SuiteName), "suiteName" },
                { new StringContent(inputData.Browser), "browser" }
            };

            // Attach image file
            if (File.Exists(inputData.Image))
            {
                var fileStream = new FileStream(inputData.Image, FileMode.Open, FileAccess.Read);
                var fileContent = new StreamContent(fileStream);
                fileContent.Headers.ContentType = new MediaTypeHeaderValue("image/png");
                formContent.Add(fileContent, "image", Path.GetFileName(inputData.Image));
            }
            else
            {
                throw new FileNotFoundException("Image file not found.", inputData.Image);
            }

            var response = _httpClient.PostAsync($"builds/{inputData.BuildId}/snapshots", formContent).Result; // Wait synchronously
            response.EnsureSuccessStatusCode();

            var responseContent = response.Content.ReadAsStringAsync().Result;
            return JsonSerializer.Deserialize<VisualSnapshotData>(responseContent);

        }
    }
}

Step 3: Run sample test

After setup up the environment and integrating the visual testing API, you can run your first web visual test

using NUnit.Framework;
using NUnit.Framework.Legacy;
using OpenQA.Selenium;
using OpenQA.Selenium.Appium;
using OpenQA.Selenium.Appium.iOS;
using OpenQA.Selenium.Support.UI;
using System;

namespace SeleniumTests
{
    public class WebSeleniumVisualTest
    {
        // Constants
        const string ProjectName = "<TEAM_CODE>";
        const string AccessKey = "mobitru_ak_......";
        const string SeleniumHost = "browserhub-us.mobitru.com";

        const string VisuaTestingHost = "visual.mobitru.com";
        const string VisualTestingBaseUrl = $"""https://{VisuaTestingHost}/billing/unit/{ProjectName}/api/v1/""";
        
        const int DefaultImplicitTimeoutSec = 3;
        const int DefaultWaitTimeoutSec = 10;

        const string VisualTestName = "visual c# demo for selenium";

        const string OpenUrl = "https://mobitru.com/";

        private RemoteWebDriver driver;
        private VisualBuildData visualBuildData;
        private readonly VisualTestingAPI visualTestingApi = new VisualTestingAPI(VisualTestingBaseUrl, AccessKey); 

        [SetUp]
        public void Setup()
        {
            // Step 1: Create a visual build
            var buildInput = new VisualBuildInputData
            {
                Name = "Build 1",
                Project = "C# Web Selenium Automation Demo",
                Branch = "main"
            };
            visualBuildData = visualTestingApi.CreateBuild(buildInput);

            var browserOptions = new ChromeOptions();

            var mobitruOptions = new Dictionary<string, object>();
            mobitruOptions.Add("enableVideo", false);
            mobitruOptions.Add("sessionTimeout", "1m");
            browserOptions.AddAdditionalOption("mobitru:options", mobitruOptions);
            var seleniumHubUrl = $"""https://{ProjectName}:{AccessKey}@{SeleniumHost}/wd/hub""";

            driver = new RemoteWebDriver(new Uri($"{seleniumHubUrl}"), browserOptions);
            driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(DefaultImplicitTimeoutSec);
        }

        [Test]
        public void TestSeleniumDemo()
        {
            // Navigate to the URL
            driver.Navigate().GoToUrl(OpenUrl);

            // Wait for the Mobitru main page to load
            WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(DefaultWaitTimeoutSec));
            By demoButtonLocator = By.CssSelector("button[class*='demo']");
            wait.Until(d => d.FindElement(demoButtonLocator).Displayed);
            // Verify the current URL
            Assert.That(driver.Url, Is.EqualTo(OpenUrl), "Current URL is incorrect.");

            // Verify the page title
            string expectedTitle = "Mobitru: Intelligent Real Device Cloud for Mobile and Cross-Browser Testing";

            Assert.That(driver.Title, Is.EqualTo(expectedTitle), "Page title is incorrect.");
            
            TakeAndSubmitScreenshot(driver, "after_login", VisualTestName, visualBuildData, visualTestingApi);
        }

        [TearDown]
        public void TearDown()
        {
            visualTestingApi.FinishBuild(visualBuildData.Id);
            driver?.Quit();
        }

        private void TakeAndSubmitScreenshot(RemoteWebDriver driver, String name, String testName, VisualBuildData buildData, VisualTestingAPI visualTestingApi)
        {
            var browserName = driver.Capabilities.GetCapability("browserName").ToString();
            string fileName = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".png"; 
            driver.GetScreenshot().SaveAsFile(fileName);
            var snapshotInput = new VisualSnapshotInputData
            {
                BuildId = buildData.Id,
                Name = name,
                TestName = testName,
                SuiteName = buildData.Project,
                Browser = browserName,
                Image = fileName
            };

            var snapshotData = visualTestingApi.SubmitSnapshot(snapshotInput);
            Console.WriteLine($"Snapshot Submitted: {snapshotData.Id}");
        }

    }
}

Scroll to Top