Skip to main content

Documentation Index

Fetch the complete documentation index at: https://jdev-e8db0569.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

Testing Strategy

Testing this library requires a multi-layered approach:
  1. Unit tests — Flutter tests with mocked MethodChannel
  2. Manual QA — Testing on real devices across scenarios

Unit Tests

Running Tests

flutter test

Test Structure

Unit tests use Flutter’s test framework with a mocked MethodChannel:
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:seon_orchestration_flutter/seon_orchestration_flutter.dart';

void main() {
  TestWidgetsFlutterBinding.ensureInitialized();

  late List<MethodCall> log;

  setUp(() {
    log = [];
  });

  void setUpChannel({dynamic Function(MethodCall)? handler}) {
    TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
        .setMockMethodCallHandler(
      const MethodChannel('seon_orchestration'),
      (call) async {
        log.add(call);
        if (handler != null) return handler(call);
        return null;
      },
    );
  }

  test('should initialize with valid config', () async {
    setUpChannel();

    await SeonOrchestration.initialize(const SeonConfig(
      baseUrl: 'https://test.com',
      token: 'test-token',
    ));

    expect(log, hasLength(1));
    expect(log.first.method, 'initialize');
    expect(log.first.arguments, {
      'baseUrl': 'https://test.com',
      'token': 'test-token',
    });
  });

  test('should start verification', () async {
    setUpChannel(handler: (call) {
      if (call.method == 'startVerification') {
        return {'status': 'completedSuccess'};
      }
      return null;
    });

    final result = await SeonOrchestration.startVerification();
    expect(result.status, SeonVerificationStatus.completedSuccess);
  });
}

Testing Error Handling

test('should throw SeonException on native error', () async {
  setUpChannel(handler: (_) {
    throw PlatformException(
      code: 'E_INITIALIZATION_FAILED',
      message: 'Initialization failed',
    );
  });

  expect(
    () => SeonOrchestration.initialize(const SeonConfig(
      baseUrl: 'https://test.com',
      token: 'bad-token',
    )),
    throwsA(isA<SeonException>()
        .having((e) => e.code, 'code', SeonErrorCode.eInitializationFailed)
        .having((e) => e.message, 'message', 'Initialization failed')),
  );
});

test('should throw SeonException on verification error', () async {
  setUpChannel(handler: (_) {
    throw PlatformException(
      code: 'E_NOT_INITIALIZED',
      message: 'Not initialized',
    );
  });

  expect(
    () => SeonOrchestration.startVerification(),
    throwsA(isA<SeonException>()
        .having((e) => e.code, 'code', SeonErrorCode.eNotInitialized)),
  );
});

Manual QA Testing

Manual testing must be performed on real devices because the SEON SDKs require actual hardware.

Prerequisites

  • Real iOS device (iOS 13+)
  • Real Android device (API 26+)
  • Valid SEON API credentials
  • Debug and release builds

Test Checklist

Initialization Tests

  • Initialize with valid credentials (both platforms)
  • Initialize with invalid baseUrl (should fail gracefully)
  • Initialize with invalid token (should fail gracefully)
  • Initialize with optional parameters (language, theme)
  • Call startVerification() before initialize() (should error with E_NOT_INITIALIZED)

Complete Flow Tests

  • Complete full verification flow successfully (both platforms)
  • Complete flow with pending status
  • Complete flow with failed status
  • Verify result object contains correct status

Cancellation Tests

  • Cancel verification mid-flow (should return interruptedByUser status)
  • Cancel at different stages (document capture, selfie, liveness)

Error Scenarios

  • Deny camera permission (should fail appropriately)
  • Deny location permission (Android: should return missingLocationPermission)
  • Deny microphone permission (should fail appropriately)
  • Call startVerification() twice simultaneously (should error with E_VERIFICATION_IN_PROGRESS)
  • Network error during verification (should return error status with message)

UI/UX Tests

  • Verify SDK UI appears correctly on both platforms
  • Verify theme setting works (light/dark)
  • Verify language setting works
  • Check UI transitions are smooth
  • Verify navigation controller handling on iOS
  • Verify transparent Activity on Android (no visual flicker)

State Management

  • App backgrounds during verification
  • App is interrupted by phone call
  • Low memory scenarios
  • Device rotation during verification

Test App Template

import 'package:flutter/material.dart';
import 'package:seon_orchestration_flutter/seon_orchestration_flutter.dart';

class TestApp extends StatefulWidget {
  const TestApp({super.key});

  @override
  State<TestApp> createState() => _TestAppState();
}

class _TestAppState extends State<TestApp> {
  String _status = 'Not initialized';

  Future<void> _testInitialize() async {
    try {
      await SeonOrchestration.initialize(const SeonConfig(
        baseUrl: 'YOUR_BASE_URL',
        token: 'YOUR_TOKEN',
        language: 'en',
      ));
      setState(() => _status = 'Initialized');
    } on SeonException catch (e) {
      setState(() => _status = 'Init failed: ${e.message}');
    }
  }

  Future<void> _testVerification() async {
    try {
      final result = await SeonOrchestration.startVerification();
      setState(() => _status = 'Result: ${result.status}');
    } on SeonException catch (e) {
      setState(() => _status = 'Verify failed: ${e.message}');
    }
  }

  Future<void> _testBeforeInit() async {
    try {
      await SeonOrchestration.startVerification();
    } on SeonException catch (e) {
      if (mounted) {
        showDialog(
          context: context,
          builder: (ctx) => AlertDialog(
            title: const Text('Expected Error'),
            content: Text(e.message),
            actions: [TextButton(onPressed: () => Navigator.pop(ctx), child: const Text('OK'))],
          ),
        );
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Padding(
          padding: const EdgeInsets.all(20),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text('Status: $_status'),
              const SizedBox(height: 16),
              ElevatedButton(onPressed: _testInitialize, child: const Text('Test Initialize')),
              ElevatedButton(onPressed: _testVerification, child: const Text('Test Verification')),
              ElevatedButton(onPressed: _testBeforeInit, child: const Text('Test Before Init (should fail)')),
            ],
          ),
        ),
      ),
    );
  }
}

Device Requirements

  • Test on real iPhone or iPad
  • Test on iOS 13, 14, 15, and latest version
  • Test on different device sizes (iPhone SE, standard, Pro Max)
  • Test in both portrait and landscape orientations
The SEON SDKs require real device hardware and will not work on simulators or emulators. Always test on physical devices.

Continuous Integration

Unit tests can be automated in CI. Device testing cannot be automated due to real device requirements.
name: Test
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: subosito/flutter-action@v2
        with:
          flutter-version: '3.x'
      - run: flutter pub get
      - run: flutter analyze
      - run: flutter test