Skip to content

kavyasoni/sapphire

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

30 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

πŸ’Ž Sapphire - Modern Mobile Test Automation Framework

License: MIT Java Appium Build Status PRs Welcome

A production-grade, open-source automation framework that makes mobile app testing significantly easier, faster, and more reliable.

Features β€’ Quick Start β€’ Documentation β€’ Examples β€’ Contributing


🎯 What is Sapphire?

Sapphire is a modern, production-ready mobile test automation framework built on top of Appium 2.x for iOS and Android testing. It transforms complex Appium commands into simple, intuitive APIs that focus on what you want to test, not how to write XPath.

The Sapphire Promise

✨ Easy - Find elements by labels, not complex XPaths πŸš€ Fast - Smart waits and retries eliminate flaky tests πŸ” Reliable - Comprehensive logging, screenshots, and detailed reports 🎯 Production-Ready - Battle-tested patterns and enterprise-grade quality 🌍 Cross-Platform - Single API for both iOS and Android πŸ”§ Extensible - Clean architecture with clear extension points


πŸŽͺ Why Sapphire?

Traditional Appium is Verbose and Brittle

// ❌ Traditional Appium - Too much boilerplate
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
By locator = By.xpath("//*[@label='Submit' or @text='Submit' or @name='Submit']");
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
if (element != null && element.isDisplayed()) {
    element.click();
}

Sapphire is Simple and Powerful

// βœ… Sapphire - Clean and intuitive
executor.clickOnElementWithLabel("Submit");

The Difference

Traditional Appium Sapphire
6+ lines of code 1 line of code
Platform-specific XPaths Cross-platform labels
Manual wait management Automatic smart waits
Complex error handling Built-in retry logic
Basic logging Rich reporting with screenshots

✨ Key Features

🎯 Core Capabilities

Label-Based Element Finding

Find elements by visible text - works across iOS and Android without platform-specific code:

executor.findElementWithLabel("Sign In");
executor.findElementContainsLabel("Sign");  // Partial match

Smart Waiting & Retries

Automatic intelligent waits with configurable timeouts:

executor.findElementWithLabel(15, "Slow Element");  // Wait up to 15 seconds
executor.performScrollAndFindElementWithLabel("Hidden Element");  // Scroll until found

Gesture Support

Built-in support for all common mobile gestures:

executor.performScrollToBottom(3);      // Scroll 3 pages down
executor.performScrollLeftToRight();    // Swipe horizontally
executor.performScroll(x1, y1, x2, y2); // Custom gestures

Screenshot on Failure

Automatic screenshot capture when tests fail:

// Configured in properties
screenshot.on.failure=true

Rich Reporting

Beautiful HTML reports with screenshots, logs, and metrics:

executor.extentReporter.startReportingForTest("Login Test");
executor.extentReporter.trackReport(LogStatus.PASS, "Login successful");

πŸ“± Platform Support

Platform Support Versions
βœ… Android Native, Hybrid, Mobile Web 7.0+
βœ… iOS Native, Hybrid, Mobile Web 12.0+
βœ… Real Devices Local & Remote All
βœ… Simulators/Emulators Full Support All
βœ… Cloud Providers Sauce Labs, BrowserStack, AWS Device Farm All

πŸ”§ Advanced Features

  • Page Object Model Support - Built-in base classes and patterns
  • Data-Driven Testing - Excel and JSON data providers
  • Parallel Execution - Run tests concurrently for faster feedback
  • Headless Execution - CI/CD ready with headless emulator support
  • Video Recording - Optional test execution recording
  • Configuration Management - Type-safe configuration with external properties
  • Logging Framework - SLF4J + Logback for structured logging
  • Allure Integration - Beautiful test reports with Allure

πŸš€ Quick Start

Prerequisites

# Java 17 or higher
java -version

# Maven 3.8+
mvn -version

# Appium 2.x
npm install -g appium@next
appium driver install uiautomator2  # For Android
appium driver install xcuitest      # For iOS

# Start Appium Server
appium

Installation

Add Sapphire to your pom.xml:

<dependency>
    <groupId>com.evig.sapphire</groupId>
    <artifactId>sapphire</artifactId>
    <version>2.0.0</version>
    <scope>test</scope>
</dependency>

Your First Test (5 Minutes)

import com.evig.sapphire.GenericExecutor;
import com.evig.sapphire.provider.DriverProvider;
import org.testng.annotations.*;

public class MyFirstTest {
    GenericExecutor executor;

    @BeforeMethod
    public void setup() throws Exception {
        // Configure capabilities
        DriverProvider.CapabilitiesBuilder builder =
            new DriverProvider.CapabilitiesBuilder(
                "/path/to/your/app.apk",  // Your app path
                "android",                 // Platform: android or ios
                "13",                      // OS version
                "emulator-5554"            // Device name
            );

        executor = new GenericExecutor(builder.build());
    }

    @Test
    public void myFirstTest() {
        // Find and click "Sign In"
        executor.clickOnElementWithLabel("Sign In");

        // Enter credentials
        executor.setTextInElementsWithLabel("test@example.com", "Email");
        executor.setTextInElementsWithLabel("password123", "Password");

        // Submit
        executor.clickOnElementWithLabel("Sign In");

        // Verify success
        assert executor.isElementsDisplayedWithLabel("Welcome");
    }

    @AfterMethod
    public void teardown() {
        executor.quitDriver();
    }
}

Run your test:

mvn test -Dtest=MyFirstTest

πŸŽ‰ That's it! Your first test is running!


πŸ“š Documentation

User Guides

Guide Description
Quick Start Get started in 5 minutes
Testing Guide Comprehensive testing guide with headless & CI/CD
Architecture Framework architecture and design
Migration Guide Upgrade from 1.x to 2.0

Core Concepts

1. Element Finding Strategies

// By label (recommended - cross-platform)
executor.findElementWithLabel("Submit");
executor.findElementContainsLabel("Sub");  // Partial match

// Case-insensitive search
executor.findElementWithLabel("submit", true);

// With custom timeout
executor.findElementWithLabel(20, "Submit");  // Wait up to 20 seconds

// By XPath (when needed)
executor.findElementByXpath("//button[@id='submit']");

// Scroll to find
WebElement el = executor.performScrollAndFindElementWithLabel("Hidden Element");

2. Element Interactions

// Click
executor.clickOnElementWithLabel("Button");
executor.clickOnElement(webElement);

// Text input
executor.setTextInElementsWithLabel("John Doe", "Name");
executor.clearElementText(webElement);

// Validation
boolean displayed = executor.isElementsDisplayedWithLabel("Success");
boolean textMatches = executor.validateElementText("Expected", element);

3. Gestures & Scrolling

// Vertical scrolling
executor.performScrollToBottom();        // Scroll to bottom
executor.performScrollToBottom(3);       // Scroll 3 pages down
executor.performScrollToTop();           // Scroll to top

// Horizontal scrolling
executor.performScrollLeftToRight();
executor.performScrollRightToLeft();

// Custom gestures
executor.performScroll(fromX, fromY, toX, toY);

4. Configuration

// Create config.properties
appium.server.url=http://localhost:4723
implicit.wait=10
screenshot.on.failure=true
headless=false

// Use type-safe configuration
SapphireConfig config = ConfigFactory.create(SapphireConfig.class);
String url = config.appiumServerUrl();

5. Reporting

// Start test reporting
executor.extentReporter.startReportingForTest("Login Test");

// Log test steps
executor.extentReporter.trackReport(LogStatus.PASS, "User logged in successfully");

// Stop reporting
executor.extentReporter.stopReportingForTest();

// Reports generated at: report/[platform]/ExtentReport.html

πŸ’‘ Examples

Complete Login Test

public class LoginTest {
    GenericExecutor executor;

    @BeforeMethod
    public void setup() throws Exception {
        DriverProvider.CapabilitiesBuilder builder =
            new DriverProvider.CapabilitiesBuilder(
                System.getenv("APP_PATH"),
                "android",
                "13",
                "emulator-5554"
            )
            .setWaitTimeInSeconds(10)
            .setExtraCapability("noReset", "true")
            .setExtraCapability("autoGrantPermissions", "true");

        executor = new GenericExecutor(builder.build());
        executor.extentReporter.startReportingForTest("Login Test");
    }

    @Test
    public void testSuccessfulLogin() {
        // Verify app launched
        assert executor.validateAppLaunchWithElements("Sign In", "Join");

        // Navigate to login
        executor.clickOnElementWithLabel("Sign In");

        // Enter credentials
        executor.setTextInElementsWithLabel("user@example.com", "Email");
        executor.setTextInElementsWithLabel("SecurePass123", "Password");

        // Submit
        executor.clickOnElementWithLabel("Sign In");
        executor.waitForSeconds(2);

        // Verify success
        assert executor.isElementsDisplayedWithLabel("Welcome", "Dashboard");

        executor.extentReporter.trackReport(LogStatus.PASS, "Login successful");
    }

    @AfterMethod
    public void teardown() {
        executor.extentReporter.stopReportingForTest();
        executor.quitDriver();
    }
}

Page Object Model

// LoginPage.java
public class LoginPage {
    private final GenericExecutor executor;

    public LoginPage(GenericExecutor executor) {
        this.executor = executor;
    }

    public void enterEmail(String email) {
        executor.setTextInElementsWithLabel(email, "Email");
    }

    public void enterPassword(String password) {
        executor.setTextInElementsWithLabel(password, "Password");
    }

    public void clickSignIn() {
        executor.clickOnElementWithLabel("Sign In");
    }

    public boolean isWelcomeDisplayed() {
        return executor.isElementsDisplayedWithLabel("Welcome");
    }
}

// Test using Page Object
@Test
public void testLoginWithPageObject() {
    LoginPage loginPage = new LoginPage(executor);
    loginPage.enterEmail("user@example.com");
    loginPage.enterPassword("password");
    loginPage.clickSignIn();
    assert loginPage.isWelcomeDisplayed();
}

Data-Driven Testing

@DataProvider
public Object[][] loginData() {
    return TestDataProvider.provideDataFromExcelFile("login_data.xlsx");
}

@Test(dataProvider = "loginData")
public void testMultipleLogins(HashMap<String, String> data) {
    String email = data.get("email");
    String password = data.get("password");

    executor.clickOnElementWithLabel("Sign In");
    executor.setTextInElementsWithLabel(email, "Email");
    executor.setTextInElementsWithLabel(password, "Password");
    executor.clickOnElementWithLabel("Sign In");

    assert executor.isElementsDisplayedWithLabel("Welcome");
}

Headless Execution (CI/CD)

// HeadlessTest.java
SapphireConfig config = ConfigFactory.create(SapphireConfig.class);

DriverProvider.CapabilitiesBuilder builder =
    new DriverProvider.CapabilitiesBuilder(app, platform, version, device)
        .setExtraCapability("isHeadless", String.valueOf(config.headless()))
        .setExtraCapability("avdArgs", "-no-window -no-audio");

// Run headless
mvn test -Dheadless=true

See examples/ for more complete examples.


πŸ—οΈ Architecture

Sapphire follows a clean, layered architecture:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              Test Layer (Your Tests)                    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                       β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚         Execution Layer (GenericExecutor)               β”‚
β”‚  β€’ Element interactions  β€’ Validation  β€’ Gestures       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                       β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚       Inspection Layer (ElementInspector)               β”‚
β”‚  β€’ Element finding  β€’ Waits  β€’ Locator strategies       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                       β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚          Driver Layer (DriverProvider)                  β”‚
β”‚  β€’ Session management  β€’ Capabilities  β€’ Configuration  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                       β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              Appium / Selenium                          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Key Design Principles:

  • Separation of Concerns - Each layer has a clear responsibility
  • Extensibility - Easy to extend with custom functionality
  • Cross-Platform - Single API for iOS and Android
  • Testability - Framework code is testable with unit tests

Read more in Architecture Documentation.


πŸ§ͺ Testing

Run Tests

# All tests
mvn test

# Specific platform
mvn test -Pandroid
mvn test -Pios

# Specific test
mvn test -Dtest=LoginTest

# Headless mode
mvn test -Dheadless=true

# With coverage
mvn test jacoco:report

Docker-Based Testing

# Start complete test environment (Appium + Emulator + Tests)
docker-compose up

# Run tests in container
docker-compose up sapphire-tests

# View logs
docker-compose logs -f

# Clean up
docker-compose down -v

CI/CD Integration

Sapphire includes pre-configured GitHub Actions:

# .github/workflows/ci.yml
- Builds on every push
- Runs tests on PR
- Multi-OS (Ubuntu, macOS)
- Multi-Java (17, 21)
- Security scanning
- Code quality checks

See Testing Guide for comprehensive testing documentation.


πŸ› οΈ Configuration

Supported Platforms & Versions

Platform Min Version Tested Versions
Android 7.0 (API 24) 7.0, 9.0, 11, 12, 13, 14
iOS 12.0 12.0, 13.0, 14.0, 15.0, 16.0, 17.0
Appium 2.0+ 2.0, 2.5
Java 17+ 17, 21

Configuration Options

Create config.properties:

# Appium Server
appium.server.url=http://localhost:4723
appium.command.timeout=60

# Waits (seconds)
implicit.wait=10
explicit.wait=30
page.load.timeout=30

# Retry
retry.count=3
retry.delay=1000

# Screenshots & Recording
screenshot.on.failure=true
screenshot.directory=./screenshots
video.recording=false
video.directory=./videos

# Reporting
report.directory=./report
log.level=INFO

# Headless
headless=false

Override with system properties:

mvn test -Dappium.server.url=http://remote:4723 -Dheadless=true

πŸ“Š Reporting

Sapphire generates comprehensive test reports:

ExtentReports

Beautiful HTML reports with screenshots, logs, and metrics.

Location: report/[platform]/ExtentReport.html

Features:

  • Test execution timeline
  • Pass/Fail statistics
  • Screenshots on failure
  • Detailed logs
  • Environment info

Allure Reports

# Generate Allure report
mvn test
allure serve target/allure-results

TestNG Reports

Default TestNG HTML reports.

Location: target/surefire-reports/index.html


🀝 Contributing

We welcome contributions! Sapphire is open-source and community-driven.

How to Contribute

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Contribution Guidelines

Read our Contributing Guide for detailed guidelines.

Code of Conduct

We follow the Contributor Covenant Code of Conduct.

Recognition

Contributors are recognized in:

  • README.md (Contributors section)
  • Release notes
  • GitHub contributors page

πŸ›‘οΈ Security

Security is a top priority. We:

βœ… Maintain zero known vulnerabilities βœ… Regularly update dependencies βœ… Scan for security issues in CI/CD βœ… Follow secure coding practices

Report Security Issues: See SECURITY.md


πŸ“„ License

Sapphire is licensed under the MIT License.

MIT License

Copyright (c) 2025 Sapphire Contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction...

You are free to:

  • βœ… Use commercially
  • βœ… Modify
  • βœ… Distribute
  • βœ… Use privately

πŸ™ Acknowledgments

Sapphire is built on top of excellent open-source projects:

Special thanks to all contributors!


πŸ“ž Support & Community

Get Help

Stay Updated

  • ⭐ Star this repository
  • πŸ‘€ Watch for releases
  • πŸ”” Subscribe to discussions

πŸ—ΊοΈ Roadmap

Current (v2.0.0)

  • βœ… Appium 2.x support
  • βœ… Java 17 support
  • βœ… Modern logging (SLF4J + Logback)
  • βœ… ExtentReports 5.x
  • βœ… Allure integration
  • βœ… Headless execution
  • βœ… Docker support
  • βœ… CI/CD ready

Upcoming (v2.1.0)

  • Enhanced fluent API
  • Improved error messages
  • More gesture patterns
  • Performance metrics

Future (v3.0.0)

  • Playwright integration (for web testing)
  • Visual regression testing
  • AI-powered element detection
  • Performance testing capabilities
  • iOS/Android inspector tool

See CHANGELOG.md for version history.


πŸ“ˆ Project Stats

GitHub stars GitHub forks GitHub watchers GitHub contributors GitHub issues GitHub pull requests


🎯 Why Choose Sapphire?

For Developers

  • πŸš€ Faster Development - Write tests 5x faster with intuitive APIs
  • 🎯 Better Reliability - Smart waits eliminate flaky tests
  • πŸ” Easier Debugging - Rich logging and screenshots
  • πŸ“š Great Documentation - Comprehensive guides and examples

For Teams

  • πŸ’° Zero Cost - Completely free and open-source
  • πŸ›‘οΈ Enterprise Quality - Production-grade code and architecture
  • 🀝 Community Support - Active community and regular updates
  • πŸ”§ Customizable - Extend and adapt to your needs

For Organizations

  • βœ… Proven - Used in production by multiple teams
  • πŸ”’ Secure - Zero known vulnerabilities
  • πŸ“Š Maintainable - Clean code, well-documented
  • 🌍 Cross-Platform - Single framework for iOS and Android

⭐ Star Us on GitHub!

If Sapphire helps you, please star the repository!

Made with ❀️ by the Sapphire Community

⬆ Back to Top

About

No description, website, or topics provided.

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors