> ## Documentation Index
> Fetch the complete documentation index at: https://jdev-e8db0569.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Testing

> Unit tests, manual QA checklists, and testing strategies.

## 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

```bash theme={null}
flutter test
```

### Test Structure

Unit tests use Flutter's test framework with a mocked MethodChannel:

```dart theme={null}
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

```dart theme={null}
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

```dart theme={null}
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

<Tabs>
  <Tab title="iOS">
    * 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
  </Tab>

  <Tab title="Android">
    * Test on real Android devices
    * Test on API levels: 26 (minimum), 29, 31, 33, and latest
    * Test on different manufacturers (Samsung, Google Pixel, etc.)
    * Test on different screen sizes
    * Test in both portrait and landscape orientations
  </Tab>
</Tabs>

<Warning>
  The SEON SDKs require real device hardware and will not work on simulators or emulators. Always test on physical devices.
</Warning>

## Continuous Integration

Unit tests can be automated in CI. Device testing cannot be automated due to real device requirements.

```yaml theme={null}
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
```
