flutter_resilience_test 0.1.0 copy "flutter_resilience_test: ^0.1.0" to clipboard
flutter_resilience_test: ^0.1.0 copied to clipboard

Repeatable Dio failure scenarios, request assertions, and readable timelines for testing Flutter and Dart API recovery.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'demo_controller.dart';

void main() => runApp(const ResilienceDemoApp());

class ResilienceDemoApp extends StatelessWidget {
  const ResilienceDemoApp({super.key});
  @override
  Widget build(BuildContext context) => MaterialApp(
    title: 'Resilience Lab',
    debugShowCheckedModeBanner: false,
    theme: ThemeData(
      useMaterial3: true,
      colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFF286455)),
      scaffoldBackgroundColor: const Color(0xFFF4F6F3),
    ),
    home: const DemoScreen(),
  );
}

class DemoScreen extends StatefulWidget {
  const DemoScreen({super.key});
  @override
  State<DemoScreen> createState() => _DemoScreenState();
}

class _DemoScreenState extends State<DemoScreen> {
  final controller = DemoController();
  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) => Scaffold(
    appBar: AppBar(
      systemOverlayStyle: SystemUiOverlayStyle.dark,
      title: const Text('Resilience Lab'),
      backgroundColor: Colors.transparent,
    ),
    body: SafeArea(
      child: ListenableBuilder(
        listenable: controller,
        builder: (context, _) => Center(
          child: ConstrainedBox(
            constraints: const BoxConstraints(maxWidth: 840),
            child: ListView(
              padding: const EdgeInsets.all(20),
              children: [
                Text(
                  'Make failure predictable.',
                  style: Theme.of(context).textTheme.headlineMedium?.copyWith(
                    fontWeight: FontWeight.bold,
                  ),
                ),
                const SizedBox(height: 8),
                const Text(
                  'Run real Dio recovery code against simulated API failures. No external server or internet connection is used.',
                ),
                const SizedBox(height: 24),
                Text(
                  'Choose a scenario',
                  style: Theme.of(context).textTheme.titleMedium,
                ),
                const SizedBox(height: 8),
                Wrap(
                  spacing: 8,
                  runSpacing: 8,
                  children: [
                    for (final scenario in DemoScenario.values)
                      ChoiceChip(
                        key: ValueKey('scenario-${scenario.name}'),
                        label: Text(scenario.label),
                        selected: controller.selected == scenario,
                        onSelected: controller.running
                            ? null
                            : (_) => controller.select(scenario),
                      ),
                  ],
                ),
                const SizedBox(height: 16),
                Text(controller.selected.description),
                const SizedBox(height: 16),
                Wrap(
                  spacing: 12,
                  runSpacing: 8,
                  children: [
                    FilledButton.icon(
                      key: const ValueKey('run-scenario'),
                      onPressed: controller.running ? null : controller.run,
                      icon: const Icon(Icons.play_arrow_rounded),
                      label: Text(
                        controller.running ? 'Running…' : 'Run scenario',
                      ),
                    ),
                    if (controller.canCancel)
                      OutlinedButton.icon(
                        key: const ValueKey('cancel-request'),
                        onPressed: controller.cancel,
                        icon: const Icon(Icons.close),
                        label: const Text('Cancel request'),
                      ),
                  ],
                ),
                const SizedBox(height: 24),
                Card(
                  margin: EdgeInsets.zero,
                  child: Padding(
                    padding: const EdgeInsets.all(20),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Semantics(
                          liveRegion: true,
                          child: Text(
                            controller.status,
                            key: const ValueKey('scenario-status'),
                            style: Theme.of(context).textTheme.titleLarge
                                ?.copyWith(
                                  fontWeight: FontWeight.bold,
                                  color: controller.status == 'Failed'
                                      ? Theme.of(context).colorScheme.error
                                      : Theme.of(context).colorScheme.primary,
                                ),
                          ),
                        ),
                        const SizedBox(height: 8),
                        Text(
                          controller.detail,
                          key: const ValueKey('scenario-detail'),
                        ),
                        if (controller.running) ...[
                          const SizedBox(height: 16),
                          const LinearProgressIndicator(),
                        ],
                        if (!controller.running && controller.attempts > 0) ...[
                          const SizedBox(height: 12),
                          Text(
                            '${controller.attempts} transport attempts observed',
                          ),
                        ],
                      ],
                    ),
                  ),
                ),
                const SizedBox(height: 24),
                Text(
                  'Request timeline',
                  style: Theme.of(context).textTheme.titleMedium,
                ),
                const SizedBox(height: 8),
                Container(
                  padding: const EdgeInsets.all(16),
                  decoration: BoxDecoration(
                    color: const Color(0xFF192C28),
                    borderRadius: BorderRadius.circular(16),
                  ),
                  child: SelectableText(
                    controller.timeline.isEmpty
                        ? 'Your request timeline will appear here.'
                        : controller.timeline,
                    key: const ValueKey('request-timeline'),
                    style: const TextStyle(
                      fontFamily: 'monospace',
                      fontSize: 13,
                      height: 1.6,
                      color: Color(0xFFDDEEE7),
                    ),
                  ),
                ),
                const SizedBox(height: 16),
                const Text(
                  'These scenarios validate application recovery. They do not simulate physical Wi-Fi changes, cellular radios, or OS background limits.',
                  style: TextStyle(fontSize: 12),
                ),
              ],
            ),
          ),
        ),
      ),
    ),
  );
}
0
likes
160
points
--
downloads

Documentation

API reference

Publisher

verified publisheremloxtech.com

Weekly Downloads

Repeatable Dio failure scenarios, request assertions, and readable timelines for testing Flutter and Dart API recovery.

Repository (GitHub)
View/report issues

Topics

#testing #dio #flutter #resilience

License

MIT (license)

Dependencies

dio

More

Packages that depend on flutter_resilience_test