Table of Contents

Code Cookbook

This comprehensive cookbook provides reusable code snippets, utility methods, and design patterns for common automation challenges. Each recipe is production-ready and follows Ranorex best practices.

📖 Quick Index

Category Recipes
Error Handling Screenshots, Logging, Recovery patterns
Timing & Waits Smart waits, Synchronization, Timeouts
Form Interactions Data entry, Validation, Complex forms
Test Data Generation, File processing, Data providers
Mobile Automation Device control, App switching, Gestures

Error Handling

Smart Screenshot Capture

Enhanced screenshot functionality with context and automatic failure handling.

using Ranorex;
using Ranorex.Core;
using System;
using System.Drawing;
using System.IO;

public static class ScreenshotHelper
{
    private static string _screenshotDirectory = Path.Combine(Environment.CurrentDirectory, "Screenshots");
    
    static ScreenshotHelper()
    {
        Directory.CreateDirectory(_screenshotDirectory);
    }
    
    /// <summary>
    /// Takes a screenshot with context information and saves it to the report
    /// </summary>
    public static void CaptureOnFailure(string testStep, Exception exception = null)
    {
        try
        {
            // Capture desktop screenshot
            var screenshot = Imaging.CaptureDesktop();
            var timestamp = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
            var filename = $"Failure_{testStep}_{timestamp}.png";
            var fullPath = Path.Combine(_screenshotDirectory, filename);
            
            // Save to file system
            screenshot.Save(fullPath);
            
            // Add to Ranorex report
            var message = exception != null ? 
                $"Test step '{testStep}' failed: {exception.Message}" : 
                $"Test step '{testStep}' failed";
                
            Report.Log(ReportLevel.Failure, message, screenshot);
            
            // Also capture active window if possible
            CaptureActiveWindow(testStep, timestamp);
        }
        catch (Exception ex)
        {
            Report.Error("Screenshot", $"Failed to capture screenshot: {ex.Message}");
        }
    }
    
    /// <summary>
    /// Captures only the active window for focused debugging
    /// </summary>
    public static void CaptureActiveWindow(string context, string timestamp = null)
    {
        try
        {
            timestamp = timestamp ?? DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
            
            // Find the currently focused window
            var activeWindow = Host.Local.Find<Form>("./form[@focused='True']").FirstOrDefault();
            if (activeWindow != null)
            {
                var windowScreenshot = activeWindow.CaptureCompressedImage();
                var filename = $"Window_{context}_{timestamp}.png";
                
                Report.Info($"Active Window - {context}", 
                    $"Captured active window: {activeWindow.Text}", windowScreenshot);
            }
        }
        catch (Exception ex)
        {
            Report.Warn("Window Screenshot", $"Could not capture active window: {ex.Message}");
        }
    }
    
    /// <summary>
    /// Captures a specific element with highlighting
    /// </summary>
    public static void CaptureElement(Element element, string description)
    {
        try
        {
            // Highlight the element first
            element.Highlight();
            Delay.Milliseconds(500);
            
            // Capture the element
            var elementImage = element.CaptureCompressedImage();
            Report.Info("Element Capture", description, elementImage);
        }
        catch (Exception ex)
        {
            Report.Warn("Element Screenshot", $"Could not capture element: {ex.Message}");
        }
    }
}

// Usage example with comprehensive error handling
public class RobustTestExample
{
    public void Run()
    {
        Host.Initialize();
        
        try
        {
            PerformLogin();
            NavigateToFeature();
            ValidateResults();
        }
        catch (RanorexException ex)
        {
            ScreenshotHelper.CaptureOnFailure("Ranorex Operation", ex);
            throw;
        }
        catch (Exception ex)
        {
            ScreenshotHelper.CaptureOnFailure("General Error", ex);
            throw;
        }
        finally
        {
            Host.Shutdown();
        }
    }
    
    private void PerformLogin()
    {
        try
        {
            var repo = MyAppRepository.Instance;
            repo.LoginDialog.UsernameField.PressKeys("testuser");
            repo.LoginDialog.PasswordField.PressKeys("password");
            repo.LoginDialog.LoginButton.Click();
        }
        catch (Exception ex)
        {
            ScreenshotHelper.CaptureOnFailure("Login Process", ex);
            throw new ApplicationException("Login failed", ex);
        }
    }
}

Retry Mechanism with Exponential Backoff

using System;
using System.Threading;

public static class RetryHelper
{
    public static T ExecuteWithRetry<T>(Func<T> operation, int maxAttempts = 3, int baseDelayMs = 1000)
    {
        Exception lastException = null;
        
        for (int attempt = 1; attempt <= maxAttempts; attempt++)
        {
            try
            {
                return operation();
            }
            catch (Exception ex)
            {
                lastException = ex;
                Report.Warn("Retry", $"Attempt {attempt} failed: {ex.Message}");
                
                if (attempt < maxAttempts)
                {
                    int delay = baseDelayMs * (int)Math.Pow(2, attempt - 1);
                    Thread.Sleep(delay);
                }
            }
        }
        
        throw new ApplicationException($"Operation failed after {maxAttempts} attempts", lastException);
    }
    
    public static void ExecuteWithRetry(Action operation, int maxAttempts = 3, int baseDelayMs = 1000)
    {
        ExecuteWithRetry(() => { operation(); return true; }, maxAttempts, baseDelayMs);
    }
}

// Usage
var result = RetryHelper.ExecuteWithRetry(() => 
{
    var element = Host.Local.FindSingle<Button>("/form/button[@text='Submit']");
    element.Click();
    return element.Text;
}, maxAttempts: 3, baseDelayMs: 500);

Timing and Waits

Smart Wait Utilities

Advanced waiting strategies that adapt to application behavior.

using Ranorex;
using System;
using System.Threading;

public static class WaitHelper
{
    /// <summary>
    /// Waits for an element to appear with custom condition
    /// </summary>
    public static bool WaitForElement(string xpath, Func<Element, bool> condition = null, 
        TimeSpan? timeout = null, string description = "element")
    {
        timeout = timeout ?? TimeSpan.FromSeconds(10);
        var endTime = DateTime.Now.Add(timeout.Value);
        
        while (DateTime.Now < endTime)
        {
            if (Host.Local.TryFindSingle(xpath, out Element element))
            {
                if (condition == null || condition(element))
                {
                    Report.Success("Wait", $"Found {description} successfully");
                    return true;
                }
            }
            
            Thread.Sleep(250);
        }
        
        Report.Failure("Wait", $"Timeout waiting for {description} after {timeout}");
        return false;
    }
    
    /// <summary>
    /// Waits for an element to disappear (useful for loading indicators)
    /// </summary>
    public static bool WaitForElementToDisappear(string xpath, TimeSpan? timeout = null, 
        string description = "element")
    {
        timeout = timeout ?? TimeSpan.FromSeconds(30);
        var endTime = DateTime.Now.Add(timeout.Value);
        
        // First, wait a bit for the element to potentially appear
        Thread.Sleep(500);
        
        while (DateTime.Now < endTime)
        {
            if (!Host.Local.TryFindSingle(xpath, out Element element) || !element.Exists)
            {
                Report.Success("Wait", $"{description} disappeared as expected");
                return true;
            }
            
            Thread.Sleep(250);
        }
        
        Report.Failure("Wait", $"Timeout: {description} did not disappear after {timeout}");
        return false;
    }
    
    /// <summary>
    /// Waits for a complex condition with polling
    /// </summary>
    public static bool WaitForCondition(Func<bool> condition, string description, 
        TimeSpan? timeout = null, int pollIntervalMs = 500)
    {
        timeout = timeout ?? TimeSpan.FromSeconds(15);
        var endTime = DateTime.Now.Add(timeout.Value);
        
        while (DateTime.Now < endTime)
        {
            try
            {
                if (condition())
                {
                    Report.Success("Wait", $"Condition met: {description}");
                    return true;
                }
            }
            catch (Exception ex)
            {
                Report.Debug("Wait", $"Condition check failed: {ex.Message}");
            }
            
            Thread.Sleep(pollIntervalMs);
        }
        
        Report.Failure("Wait", $"Timeout waiting for condition: {description}");
        return false;
    }
    
    /// <summary>
    /// Waits for page to load (web applications)
    /// </summary>
    public static bool WaitForPageLoad(string domain, TimeSpan? timeout = null)
    {
        return WaitForCondition(() =>
        {
            var webDoc = Host.Local.FindSingle<WebDocument>($"/dom[@domain='{domain}']");
            return webDoc.PageUrl != "about:blank" && 
                   !webDoc.PageUrl.Contains("loading") &&
                   webDoc.ReadyState == "complete";
        }, $"page load for domain {domain}", timeout);
    }
}

// Usage examples
public class WaitExamples
{
    public void DemonstrateWaits()
    {
        // Wait for element to be enabled
        WaitHelper.WaitForElement("/form/button[@text='Submit']", 
            element => element.Enabled, 
            TimeSpan.FromSeconds(5), 
            "Submit button to be enabled");
        
        // Wait for loading spinner to disappear
        WaitHelper.WaitForElementToDisappear("/form//*[@class='loading-spinner']", 
            TimeSpan.FromSeconds(30), 
            "loading spinner");
        
        // Wait for complex business condition
        WaitHelper.WaitForCondition(() =>
        {
            var statusLabel = Host.Local.FindSingle<Text>("/form/text[@name='status']");
            return statusLabel.Text == "Processing Complete";
        }, "processing to complete");
        
        // Wait for web page to load
        WaitHelper.WaitForPageLoad("example.com");
    }
}

Form Interactions

Advanced Form Automation

Comprehensive form handling with validation and error recovery.

using Ranorex;
using System;
using System.Collections.Generic;
using System.Linq;

public class FormAutomationHelper
{
    /// <summary>
    /// Fills a form using a dictionary of field names and values
    /// </summary>
    public static void FillForm(Dictionary<string, string> formData, string formXPath = null)
    {
        foreach (var field in formData)
        {
            FillField(field.Key, field.Value, formXPath);
        }
    }
    
    /// <summary>
    /// Fills a single form field with intelligent field detection
    /// </summary>
    public static void FillField(string fieldName, string value, string formXPath = null)
    {
        try
        {
            string baseXPath = formXPath ?? "//";
            Element field = null;
            
            // Try different field identification strategies
            string[] patterns = {
                $"{baseXPath}*[@name='{fieldName}']",
                $"{baseXPath}*[@id='{fieldName}']",
                $"{baseXPath}*[@automationid='{fieldName}']",
                $"{baseXPath}text[@name='{fieldName}']",
                $"{baseXPath}input[@name='{fieldName}']",
                $"{baseXPath}*[contains(@placeholder, '{fieldName}')]",
                $"{baseXPath}*[preceding-sibling::*[contains(text(), '{fieldName}')]]"
            };
            
            foreach (var pattern in patterns)
            {
                if (Host.Local.TryFindSingle(pattern, out field))
                {
                    break;
                }
            }
            
            if (field == null)
            {
                throw new ElementNotFoundException($"Could not find field: {fieldName}");
            }
            
            // Handle different field types
            HandleFieldInput(field, value, fieldName);
            
        }
        catch (Exception ex)
        {
            Report.Failure("Form Fill", $"Failed to fill field '{fieldName}': {ex.Message}");
            ScreenshotHelper.CaptureOnFailure($"FillField_{fieldName}", ex);
            throw;
        }
    }
    
    private static void HandleFieldInput(Element field, string value, string fieldName)
    {
        // Ensure field is visible and enabled
        if (!field.Visible)
        {
            throw new InvalidOperationException($"Field '{fieldName}' is not visible");
        }
        
        if (field is Text textField)
        {
            // Regular text input
            textField.Click();
            textField.PressKeys("{Ctrl}a"); // Select all existing text
            textField.PressKeys(value);
            Report.Info("Form", $"Filled text field '{fieldName}' with: {value}");
        }
        else if (field is ComboBox comboBox)
        {
            // Dropdown selection
            comboBox.Click();
            Delay.Milliseconds(300);
            comboBox.PressKeys(value);
            comboBox.PressKeys("{Return}");
            Report.Info("Form", $"Selected '{value}' in dropdown '{fieldName}'");
        }
        else if (field is CheckBox checkBox)
        {
            // Checkbox handling
            bool shouldCheck = value.ToLower() == "true" || value == "1" || value.ToLower() == "yes";
            if (checkBox.Checked != shouldCheck)
            {
                checkBox.Click();
            }
            Report.Info("Form", $"Set checkbox '{fieldName}' to: {shouldCheck}");
        }
        else if (field is RadioButton radioButton)
        {
            // Radio button
            if (value.ToLower() == "true" || value == "1")
            {
                radioButton.Click();
                Report.Info("Form", $"Selected radio button '{fieldName}'");
            }
        }
        else
        {
            // Generic element - try clicking and typing
            field.Click();
            field.PressKeys("{Ctrl}a");
            field.PressKeys(value);
            Report.Info("Form", $"Filled generic field '{fieldName}' with: {value}");
        }
        
        // Brief pause to allow field processing
        Delay.Milliseconds(200);
    }
    
    /// <summary>
    /// Validates form field values
    /// </summary>
    public static Dictionary<string, string> ValidateForm(Dictionary<string, string> expectedValues, 
        string formXPath = null)
    {
        var validationResults = new Dictionary<string, string>();
        
        foreach (var expected in expectedValues)
        {
            try
            {
                string actualValue = GetFieldValue(expected.Key, formXPath);
                
                if (actualValue == expected.Value)
                {
                    validationResults[expected.Key] = "PASS";
                    Report.Success("Validation", $"Field '{expected.Key}' has correct value: {actualValue}");
                }
                else
                {
                    validationResults[expected.Key] = $"FAIL: Expected '{expected.Value}', got '{actualValue}'";
                    Report.Failure("Validation", validationResults[expected.Key]);
                }
            }
            catch (Exception ex)
            {
                validationResults[expected.Key] = $"ERROR: {ex.Message}";
                Report.Error("Validation", $"Failed to validate field '{expected.Key}': {ex.Message}");
            }
        }
        
        return validationResults;
    }
    
    private static string GetFieldValue(string fieldName, string formXPath)
    {
        string baseXPath = formXPath ?? "//";
        string[] patterns = {
            $"{baseXPath}*[@name='{fieldName}']",
            $"{baseXPath}*[@id='{fieldName}']",
            $"{baseXPath}text[@name='{fieldName}']",
            $"{baseXPath}input[@name='{fieldName}']"
        };
        
        foreach (var pattern in patterns)
        {
            if (Host.Local.TryFindSingle(pattern, out Element field))
            {
                if (field is Text textField)
                    return textField.Text;
                else if (field is ComboBox comboBox)
                    return comboBox.Text;
                else if (field is CheckBox checkBox)
                    return checkBox.Checked.ToString();
                else
                    return field.GetAttributeValueOrDefault("Value", field.GetAttributeValueOrDefault("Text", ""));
            }
        }
        
        throw new ElementNotFoundException($"Could not find field: {fieldName}");
    }
}

// Usage example
public class FormExampleUsage
{
    public void FillRegistrationForm()
    {
        var formData = new Dictionary<string, string>
        {
            ["firstName"] = "John",
            ["lastName"] = "Doe",
            ["email"] = "john.doe@example.com",
            ["country"] = "United States",
            ["agreeToTerms"] = "true",
            ["newsletter"] = "false"
        };
        
        // Fill the form
        FormAutomationHelper.FillForm(formData, "/form[@title='Registration']");
        
        // Submit the form
        var submitButton = Host.Local.FindSingle<Button>("/form[@title='Registration']/button[@text='Submit']");
        submitButton.Click();
        
        // Wait for confirmation
        WaitHelper.WaitForElement("//*[contains(text(), 'Registration successful')]", 
            timeout: TimeSpan.FromSeconds(10), description: "registration confirmation");
            
        // Validate the form was submitted correctly (if form stays visible)
        var validationResults = FormAutomationHelper.ValidateForm(formData, "/form[@title='Registration']");
        
        foreach (var result in validationResults.Where(r => r.Value != "PASS"))
        {
            Report.Warn("Form Validation", $"{result.Key}: {result.Value}");
        }
    }
}

Test Data

Advanced Data Generation

Comprehensive test data generation for realistic testing scenarios.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

public static class TestDataGenerator
{
    private static readonly Random _random = new Random();
    
    private static readonly string[] FirstNames = {
        "James", "Mary", "John", "Patricia", "Robert", "Jennifer", "Michael", "Linda",
        "William", "Elizabeth", "David", "Barbara", "Richard", "Susan", "Joseph", "Jessica"
    };
    
    private static readonly string[] LastNames = {
        "Smith", "Johnson", "Williams", "Brown", "Jones", "Garcia", "Miller", "Davis",
        "Rodriguez", "Martinez", "Hernandez", "Lopez", "Gonzalez", "Wilson", "Anderson", "Thomas"
    };
    
    private static readonly string[] EmailDomains = {
        "gmail.com", "yahoo.com", "hotmail.com", "outlook.com", "example.com", "test.com"
    };
    
    private static readonly string[] Countries = {
        "United States", "Canada", "United Kingdom", "Germany", "France", "Australia", "Japan", "Brazil"
    };
    
    public static string RandomString(int length, bool includeNumbers = true, bool includeSpecialChars = false)
    {
        var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
        
        if (includeNumbers)
            chars += "0123456789";
            
        if (includeSpecialChars)
            chars += "!@#$%^&*()_+-=[]{}|;:,.<>?";
        
        return new string(Enumerable.Repeat(chars, length)
            .Select(s => s[_random.Next(s.Length)]).ToArray());
    }
    
    public static string RandomFirstName() => FirstNames[_random.Next(FirstNames.Length)];
    public static string RandomLastName() => LastNames[_random.Next(LastNames.Length)];
    public static string RandomCountry() => Countries[_random.Next(Countries.Length)];
    
    public static string RandomEmail(string firstName = null, string lastName = null)
    {
        firstName = firstName ?? RandomFirstName();
        lastName = lastName ?? RandomLastName();
        var domain = EmailDomains[_random.Next(EmailDomains.Length)];
        var separator = _random.Next(2) == 0 ? "." : "_";
        var number = _random.Next(2) == 0 ? _random.Next(1, 999).ToString() : "";
        
        return $"{firstName.ToLower()}{separator}{lastName.ToLower()}{number}@{domain}";
    }
    
    public static string RandomPhoneNumber(string format = "###-###-####")
    {
        var result = format;
        foreach (char c in result.ToCharArray())
        {
            if (c == '#')
            {
                result = result.ReplaceFirst("#", _random.Next(0, 10).ToString());
            }
        }
        return result;
    }
    
    public static DateTime RandomDateBetween(DateTime start, DateTime end)
    {
        var range = end - start;
        var randomDays = _random.Next((int)range.TotalDays);
        return start.AddDays(randomDays);
    }
    
    public static DateTime RandomBirthdate(int minAge = 18, int maxAge = 80)
    {
        var today = DateTime.Today;
        var start = today.AddYears(-maxAge);
        var end = today.AddYears(-minAge);
        return RandomDateBetween(start, end);
    }
    
    // Extension method helper
    private static string ReplaceFirst(this string text, string search, string replace)
    {
        int pos = text.IndexOf(search);
        if (pos < 0) return text;
        return text.Substring(0, pos) + replace + text.Substring(pos + search.Length);
    }
}

// Complete user data generation
public class TestUser
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
    public string Phone { get; set; }
    public string Country { get; set; }
    public DateTime BirthDate { get; set; }
    public string Username { get; set; }
    public string Password { get; set; }
    
    public static TestUser GenerateRandomUser()
    {
        var firstName = TestDataGenerator.RandomFirstName();
        var lastName = TestDataGenerator.RandomLastName();
        
        return new TestUser
        {
            FirstName = firstName,
            LastName = lastName,
            Email = TestDataGenerator.RandomEmail(firstName, lastName),
            Phone = TestDataGenerator.RandomPhoneNumber(),
            Country = TestDataGenerator.RandomCountry(),
            BirthDate = TestDataGenerator.RandomBirthdate(),
            Username = $"{firstName.ToLower()}{lastName.ToLower()}{TestDataGenerator.RandomString(3, true, false)}",
            Password = TestDataGenerator.RandomString(12, true, true)
        };
    }
}

File Processing Utilities

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;

public static class FileDataProvider
{
    /// <summary>
    /// Reads CSV data with header support
    /// </summary>
    public static List<Dictionary<string, string>> ReadCsv(string filePath, bool hasHeaders = true)
    {
        var result = new List<Dictionary<string, string>>();
        var lines = File.ReadAllLines(filePath);
        
        if (lines.Length == 0) return result;
        
        string[] headers = null;
        int startIndex = 0;
        
        if (hasHeaders)
        {
            headers = ParseCsvLine(lines[0]);
            startIndex = 1;
        }
        else
        {
            // Generate column names: Column1, Column2, etc.
            var firstLine = ParseCsvLine(lines[0]);
            headers = firstLine.Select((v, i) => $"Column{i + 1}").ToArray();
        }
        
        for (int i = startIndex; i < lines.Length; i++)
        {
            var values = ParseCsvLine(lines[i]);
            var row = new Dictionary<string, string>();
            
            for (int j = 0; j < headers.Length && j < values.Length; j++)
            {
                row[headers[j]] = values[j];
            }
            
            result.Add(row);
        }
        
        return result;
    }
    
    private static string[] ParseCsvLine(string line)
    {
        var result = new List<string>();
        var current = new StringBuilder();
        bool inQuotes = false;
        
        for (int i = 0; i < line.Length; i++)
        {
            char c = line[i];
            
            if (c == '"')
            {
                inQuotes = !inQuotes;
            }
            else if (c == ',' && !inQuotes)
            {
                result.Add(current.ToString().Trim());
                current.Clear();
            }
            else
            {
                current.Append(c);
            }
        }
        
        result.Add(current.ToString().Trim());
        return result.ToArray();
    }
    
    /// <summary>
    /// Reads JSON test data
    /// </summary>
    public static T ReadJson<T>(string filePath)
    {
        var jsonContent = File.ReadAllText(filePath);
        return JsonSerializer.Deserialize<T>(jsonContent);
    }
    
    /// <summary>
    /// Writes test results to JSON
    /// </summary>
    public static void WriteJson<T>(string filePath, T data)
    {
        var options = new JsonSerializerOptions { WriteIndented = true };
        var jsonContent = JsonSerializer.Serialize(data, options);
        File.WriteAllText(filePath, jsonContent);
    }
}

Browser & Web

JavaScript Execution and Web Utilities

using Ranorex;
using Ranorex.Core;
using System;
using System.Collections.Generic;

public static class WebAutomationHelper
{
    /// <summary>
    /// Executes JavaScript and returns the result
    /// </summary>
    public static T ExecuteScript<T>(string script, string domain = null)
    {
        try
        {
            var webDoc = domain != null ? 
                Host.Local.FindSingle<WebDocument>($"/dom[@domain='{domain}']") :
                Host.Local.FindSingle<WebDocument>("/dom");
                
            var result = webDoc.ExecuteScript(script);

            if (result == null || result is DBNull)
            {
                return default(T);
            }
            
            if (result is T)
                return (T)result;
            else
                return (T)Convert.ChangeType(result, typeof(T));
        }
        catch (Exception ex)
        {
            Report.Error("JavaScript", $"Failed to execute script: {ex.Message}");
            throw;
        }
    }
    
    /// <summary>
    /// Waits for jQuery to complete (if jQuery is available)
    /// </summary>
    public static bool WaitForJQuery(TimeSpan? timeout = null)
    {
        timeout = timeout ?? TimeSpan.FromSeconds(10);
        
        return WaitHelper.WaitForCondition(() =>
        {
            try
            {
                var jqueryActive = ExecuteScript<long>("return jQuery.active || 0");
                return jqueryActive == 0;
            }
            catch
            {
                return true; // jQuery not available, assume ready
            }
        }, "jQuery to complete", timeout);
    }
    
    /// <summary>
    /// Scrolls an element into view
    /// </summary>
    public static void ScrollIntoView(Element element)
    {
        try
        {
            var webElement = element as WebElement;
            if (webElement != null)
            {
                var script = "arguments[0].scrollIntoView({behavior: 'smooth', block: 'center'});";
                webElement.WebDocument.ExecuteScript(script, webElement);
            }
            else
            {
                // For desktop elements, use MoveTo to bring into view
                element.MoveTo();
            }
        }
        catch (Exception ex)
        {
            Report.Warn("Scroll", $"Could not scroll element into view: {ex.Message}");
        }
    }
    
    /// <summary>
    /// Manages browser cookies
    /// </summary>
    public static void SetCookie(string name, string value, string domain = null)
    {
        var script = domain != null ?
            $"document.cookie = '{name}={value}; domain={domain}; path=/'" :
            $"document.cookie = '{name}={value}; path=/'";
            
        ExecuteScript<object>(script);
        Report.Info("Cookie", $"Set cookie: {name}={value}");
    }
    
    public static string GetCookie(string name)
    {
        var script = $@"
            var nameEQ = '{name}=';
            var ca = document.cookie.split(';');
            for(var i=0;i < ca.length;i++) {{
                var c = ca[i];
                while (c.charAt(0)==' ') c = c.substring(1,c.length);
                if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
            }}
            return null;";
            
        return ExecuteScript<string>(script);
    }
    
    /// <summary>
    /// Handles file uploads
    /// </summary>
    public static void UploadFile(Element fileInput, string filePath)
    {
        try
        {
            if (!File.Exists(filePath))
            {
                throw new FileNotFoundException($"Upload file not found: {filePath}");
            }
            
            fileInput.Click();
            fileInput.PressKeys(filePath);
            
            Report.Info("File Upload", $"Uploaded file: {filePath}");
        }
        catch (Exception ex)
        {
            Report.Failure("File Upload", $"Failed to upload file: {ex.Message}");
            throw;
        }
    }
}

Mobile Automation

Mobile Device Control and Gestures

using Ranorex;
using Ranorex.Core.Remoting;
using System;

public static class MobileHelper
{
    /// <summary>
    /// Switches between mobile applications
    /// </summary>
    public static void SwitchToApp(string packageName, bool clearAppData = false)
    {
        try
        {
            if (clearAppData)
            {
                Mobile.ClearAppData(packageName);
            }
            
            Mobile.RunApplication(packageName, true);
            Report.Info("Mobile", $"Switched to app: {packageName}");
            
            // Wait for the app's main window to appear
            WaitHelper.WaitForCondition(() =>
            {
                var app = Host.Local.FindSingle<MobileApp>($"/mobileapp[@packagename='{packageName}']");
                return app.Visible;
            }, $"app '{packageName}' to load", TimeSpan.FromSeconds(20));
        }
        catch (Exception ex)
        {
            Report.Failure("Mobile", $"Failed to switch to app {packageName}: {ex.Message}");
            throw;
        }
    }
    
    /// <summary>
    /// Performs swipe gestures
    /// </summary>
    public static void SwipeElement(Element element, SwipeDirection direction, int distance = 200)
    {
        try
        {
            var bounds = element.Bounds;
            var centerX = bounds.X + bounds.Width / 2;
            var centerY = bounds.Y + bounds.Height / 2;
            
            Point startPoint, endPoint;
            
            switch (direction)
            {
                case SwipeDirection.Up:
                    startPoint = new Point(centerX, centerY + distance / 2);
                    endPoint = new Point(centerX, centerY - distance / 2);
                    break;
                case SwipeDirection.Down:
                    startPoint = new Point(centerX, centerY - distance / 2);
                    endPoint = new Point(centerX, centerY + distance / 2);
                    break;
                case SwipeDirection.Left:
                    startPoint = new Point(centerX + distance / 2, centerY);
                    endPoint = new Point(centerX - distance / 2, centerY);
                    break;
                case SwipeDirection.Right:
                    startPoint = new Point(centerX - distance / 2, centerY);
                    endPoint = new Point(centerX + distance / 2, centerY);
                    break;
                default:
                    throw new ArgumentException($"Invalid swipe direction: {direction}");
            }
            
            Touch.StartTouch(startPoint);
            Touch.MoveTouch(endPoint);
            Touch.EndTouch();
            
            Report.Info("Mobile", $"Swiped {direction} on element");
        }
        catch (Exception ex)
        {
            Report.Failure("Mobile", $"Failed to swipe: {ex.Message}");
            throw;
        }
    }
    
    /// <summary>
    /// Handles device orientation
    /// </summary>
    public static void SetOrientation(DeviceOrientation orientation)
    {
        try
        {
            Mobile.Device.Orientation = orientation;
            
            // Wait for the orientation to change
            WaitHelper.WaitForCondition(() => Mobile.Device.Orientation == orientation,
                $"orientation to be {orientation}", TimeSpan.FromSeconds(10));
                
            Report.Info("Mobile", $"Set device orientation to: {orientation}");
        }
        catch (Exception ex)
        {
            Report.Failure("Mobile", $"Failed to set orientation: {ex.Message}");
            throw;
        }
    }
    
    /// <summary>
    /// Simulates device back button
    /// </summary>
    public static void PressBackButton()
    {
        try
        {
            Mobile.PressHardwareButton(HardwareButton.Back);
            Report.Info("Mobile", "Pressed back button");
        }
        catch (Exception ex)
        {
            Report.Failure("Mobile", $"Failed to press back button: {ex.Message}");
            throw;
        }
    }
}

public enum SwipeDirection
{
    Up,
    Down,
    Left,
    Right
}

Utilities & Helpers

Common Automation Patterns

using Ranorex;
using System;
using System.Collections.Generic;
using System.Linq;

public static class AutomationUtilities
{
    /// <summary>
    /// Finds and clicks an element with retry logic
    /// </summary>
    public static bool ClickElementSafely(string xpath, TimeSpan? timeout = null, string description = null)
    {
        description = description ?? $"element at {xpath}";
        timeout = timeout ?? TimeSpan.FromSeconds(10);
        
        return RetryHelper.ExecuteWithRetry(() =>
        {
            var element = Host.Local.FindSingle<Element>(xpath, (int)timeout.Value.TotalMilliseconds);
            
            if (!element.Visible)
            {
                throw new InvalidOperationException($"{description} is not visible");
            }
            
            if (!element.Enabled)
            {
                throw new InvalidOperationException($"{description} is not enabled");
            }
            
            element.Click();
            Report.Info("Click", $"Successfully clicked {description}");
            return true;
        }, maxAttempts: 3);
    }
    
    /// <summary>
    /// Gets all text content from a container element
    /// </summary>
    public static List<string> ExtractAllText(Element container)
    {
        var textElements = container.Find<Text>(".//*");
        return textElements.Select(t => t.Text?.Trim())
                          .Where(text => !string.IsNullOrWhiteSpace(text))
                          .ToList();
    }
    
    /// <summary>
    /// Validates element properties
    /// </summary>
    public static bool ValidateElementProperties(Element element, Dictionary<string, object> expectedProperties)
    {
        bool allValid = true;
        
        foreach (var property in expectedProperties)
        {
            try
            {
                var actualValue = element.GetAttributeValue(property.Key);
                
                if (!actualValue.Equals(property.Value))
                {
                    Report.Failure("Validation", 
                        $"Property '{property.Key}': Expected '{property.Value}', got '{actualValue}'");
                    allValid = false;
                }
                else
                {
                    Report.Success("Validation", 
                        $"Property '{property.Key}' has correct value: {actualValue}");
                }
            }
            catch (Exception ex)
            {
                Report.Error("Validation", $"Failed to get property '{property.Key}': {ex.Message}");
                allValid = false;
            }
        }
        
        return allValid;
    }
    
    /// <summary>
    /// Performs bulk operations on element collections
    /// </summary>
    public static void ProcessElementCollection<T>(IList<T> elements, Action<T, int> action) where T : Element
    {
        for (int i = 0; i < elements.Count; i++)
        {
            try
            {
                action(elements[i], i);
            }
            catch (Exception ex)
            {
                Report.Warn("Collection Processing", 
                    $"Failed to process element {i}: {ex.Message}");
            }
        }
    }
}

/// <summary>
/// Application state management
/// </summary>
public static class ApplicationState
{
    private static readonly Dictionary<string, object> _state = new Dictionary<string, object>();
    
    public static void Set(string key, object value)
    {
        _state[key] = value;
        Report.Debug("State", $"Set {key} = {value}");
    }
    
    public static T Get<T>(string key, T defaultValue = default(T))
    {
        if (_state.TryGetValue(key, out object value))
        {
            return (T)value;
        }
        return defaultValue;
    }
    
    public static void Clear()
    {
        _state.Clear();
        Report.Debug("State", "Cleared application state");
    }
}

Next Steps

This cookbook provides the foundation for building robust automation solutions. For more advanced scenarios:

  1. Advanced Integration - Database integration, API testing, CI/CD patterns
  2. Desktop Patterns - Windows-specific automation techniques
  3. Web Patterns - Modern web application automation
  4. Mobile Patterns - iOS and Android automation patterns

Contributing

Have a useful pattern or utility to share? Follow these guidelines:

  • Document thoroughly - Include purpose, parameters, and usage examples
  • Handle errors gracefully - Use try-catch and provide meaningful error messages
  • Follow naming conventions - Use descriptive method and variable names
  • Test comprehensively - Ensure your code works in different scenarios

These patterns form the building blocks for scalable, maintainable automation frameworks. Use them as starting points and adapt them to your specific needs!