Basic example
Source code Click here to view the full source code of this example
This example shows the basic usage of Disco. In particular, it shows how to create a provider, how to scope it, how to use it in a widget and finally how to test it.
import 'package:disco/disco.dart';import 'package:flutter/material.dart';
abstract class Model extends ChangeNotifier { void incrementCounter();
int get counter;}
class ModelImplementation extends Model { int _counter = 0;
@override int get counter => _counter;
@override void incrementCounter() { _counter++; notifyListeners(); }}
final modelProvider = Provider<Model>((context) => ModelImplementation());
void main() { runApp(const MainApp());}
class MainApp extends StatelessWidget { const MainApp({super.key});
@override Widget build(BuildContext context) { return MaterialApp( title: 'Disco Example', theme: ThemeData( primarySwatch: Colors.blue, ), home: const MyHomePage(), ); }}
class MyHomePage extends StatelessWidget { const MyHomePage({super.key});
@override Widget build(BuildContext context) { // Provide the modelProvider to descendants return ProviderScope( providers: [modelProvider], // This builder gives a descendant context, only descendants can access // this scope child: Builder( builder: (context) { // retrieve the model final model = modelProvider.of(context); return Scaffold( body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ const Text( 'You have pushed the button this many times:', ), // Rebuilds this widget when the model changes ListenableBuilder( listenable: model, builder: (context, child) { return Text(model.counter.toString()); }, ), ], ), ), floatingActionButton: FloatingActionButton( // increment the counter when the button is pressed onPressed: model.incrementCounter, child: const Icon(Icons.add), ), ); }, ), ); }}
Testing
import 'package:disco/disco.dart';import 'package:example/main.dart';import 'package:flutter/material.dart';import 'package:flutter_test/flutter_test.dart';
class MockModel extends Model { int _counter = 5;
@override int get counter => _counter;
@override void incrementCounter() { _counter += 2; notifyListeners(); }}
void main() { testWidgets( 'Counter increments when FAB is pressed', (WidgetTester tester) async { // Build the app and trigger a frame. await tester.pumpWidget(const MainApp());
// Verify that the initial counter value is 0. expect( find.text('You have pushed the button this many times:'), findsOneWidget, ); expect(find.text('0'), findsOneWidget);
// Tap the floating action button to increment the counter. await tester.tap(find.byType(FloatingActionButton)); // Rebuild the widget after the state has changed. await tester.pump();
// Verify that the counter has incremented to 1. expect(find.text('1'), findsOneWidget); }, ); testWidgets('Counter displays mocked value', (WidgetTester tester) async { await tester.pumpWidget( ProviderScopeOverride( overrides: [ modelProvider.overrideWithValue(MockModel()), ], child: const MainApp(), ), );
// Verify that the initial counter value is the mocked value (5). expect( find.text('You have pushed the button this many times:'), findsOneWidget, ); expect(find.text('5'), findsOneWidget);
// Tap the floating action button to increment the counter. await tester.tap(find.byType(FloatingActionButton)); // Rebuild the widget after the state has changed. await tester.pump();
// Verify that the counter has incremented to 7. expect(find.text('7'), findsOneWidget); });}