Modern QA2026Camera-Based Feature Testing — tiles
Log inJoin
51 / 66 · 09 Mobile & Cross-Platform Testing · Testing Voice Interfaces and Camera-Based Features← prev⊞ allnext →☰ Read as one page

9.3Camera-Based Feature Testing

AR features, barcode scanners, document capture, and face detection all require the camera, which makes them challenging to test in automated pipelines.

Testing Barcode Scanners

# Testing barcode scanner with synthetic camera input
def test_barcode_scanner(driver):
    """Test barcode scanning using a pre-recorded camera feed."""

    # Appium can inject camera images on supported devices
    driver.push_file(
        "/sdcard/DCIM/test_barcode.png",
        source_path="test_data/barcode_ean13.png"
    )

    # Navigate to scanner
    driver.find_element(AppiumBy.ACCESSIBILITY_ID, "scan-barcode-btn").click()

    # On emulators, use a virtual camera scene
    driver.execute_script("mobile: shell", {
        "command": "am",
        "args": ["broadcast", "-a", "com.testapp.INJECT_CAMERA_FRAME",
                 "--es", "image_path", "/sdcard/DCIM/test_barcode.png"]
    })

    # Verify barcode was decoded
    result = driver.find_element(AppiumBy.ACCESSIBILITY_ID, "scan-result")
    assert result.text == "4006381333931"  # Expected EAN-13

def test_barcode_scanner_with_various_formats(driver):
    """Test that the scanner handles multiple barcode formats."""
    test_barcodes = [
        {"file": "barcode_ean13.png", "expected": "4006381333931", "format": "EAN-13"},
        {"file": "barcode_qr.png", "expected": "https://example.com/product/123", "format": "QR"},
        {"file": "barcode_code128.png", "expected": "ABC-12345", "format": "Code 128"},
        {"file": "barcode_upc.png", "expected": "042100005264", "format": "UPC-A"},
    ]

    for barcode in test_barcodes:
        driver.push_file(
            "/sdcard/DCIM/test_barcode.png",
            source_path=f"test_data/{barcode['file']}"
        )

        driver.find_element(AppiumBy.ACCESSIBILITY_ID, "scan-barcode-btn").click()
        driver.execute_script("mobile: shell", {
            "command": "am",
            "args": ["broadcast", "-a", "com.testapp.INJECT_CAMERA_FRAME",
                     "--es", "image_path", "/sdcard/DCIM/test_barcode.png"]
        })

        result = driver.find_element(AppiumBy.ACCESSIBILITY_ID, "scan-result")
        assert result.text == barcode["expected"], \
            f"{barcode['format']} barcode: expected {barcode['expected']}, got {result.text}"

        # Go back for next test
        driver.back()

Testing AR Features

def test_ar_furniture_placement(driver):
    """Test AR furniture placement feature with synthetic camera."""

    # Inject a synthetic room scene
    driver.push_file(
        "/sdcard/DCIM/ar_test_room.jpg",
        source_path="test_data/ar_room_scene.jpg"
    )

    # Navigate to AR viewer
    driver.find_element(AppiumBy.ACCESSIBILITY_ID, "ar-viewer-btn").click()

    # Select a furniture item
    driver.find_element(AppiumBy.ACCESSIBILITY_ID, "furniture-sofa").click()

    # Verify AR session started
    ar_canvas = driver.find_element(AppiumBy.ACCESSIBILITY_ID, "ar-canvas")
    assert ar_canvas.is_displayed()

    # Verify placement controls are available
    rotate_btn = driver.find_element(AppiumBy.ACCESSIBILITY_ID, "ar-rotate")
    scale_btn = driver.find_element(AppiumBy.ACCESSIBILITY_ID, "ar-scale")
    assert rotate_btn.is_displayed()
    assert scale_btn.is_displayed()

def test_camera_permission_denied_gracefully(driver):
    """App should handle camera permission denial without crashing."""
    # Deny camera permission
    driver.find_element(AppiumBy.ACCESSIBILITY_ID, "scan-barcode-btn").click()

    # Dismiss permission dialog with "Deny"
    driver.find_element(
        AppiumBy.ID, "com.android.permissioncontroller:id/permission_deny_button"
    ).click()

    # App should show a friendly message, not crash
    error_msg = driver.find_element(AppiumBy.ACCESSIBILITY_ID, "camera-denied-message")
    assert error_msg.is_displayed()
    assert "camera" in error_msg.text.lower()