Search code examples
testingfluttersharedpreferences

Testing shared_preferences on flutter


I'm writing a flutter application and I'm having this issue when writing the tests. This method is supposed to write data into TextFields and tap a button which saves this data in SharedPrefs:

testWidgets('Click on login saves the credentials',
      (WidgetTester tester) async {

    await tester.pumpWidget(MyApp());

    await tester.enterText(find.byKey(Key('phoneInput')), 'test');
    await tester.enterText(find.byKey(Key('passwordInput')), 'test');
    await tester.tap(find.byIcon(Icons.lock));

    SharedPreferences prefs = await SharedPreferences.getInstance();
    expect(prefs.getString('phone'), 'test');
    expect(prefs.getString('password'), 'test');
  });

This test will fail getting the SharedPreferences instance with this error:

The following TimeoutException was thrown running a test:
TimeoutException after 0:00:03.500000: The test exceeded the timeout. It may have hung.
Consider using "addTime" to increase the timeout before expensive operations.

Update: Seems that the problem is not actually the timeout because even with 60 seconds the test is not capable of resolving the SharedPreferences instance.


Solution

  • You needed to mock getAll from shared_preferences (ref: https://pub.dartlang.org/packages/shared_preferences)

    Here's the sample code:

    import 'package:shared_preferences/shared_preferences.dart';
    import 'package:flutter/services.dart'; // <-- needed for `MethodChannel`
    
    void main() {
    
      setUpAll(() {
        const MethodChannel('plugins.flutter.io/shared_preferences')
            .setMockMethodCallHandler((MethodCall methodCall) async {
          if (methodCall.method == 'getAll') {
            return <String, dynamic>{}; // set initial values here if desired
          }
          return null;
        });
      });
    
      testWidgets('Click on login saves the credentials',
          (WidgetTester tester) async {
        await tester.pumpWidget(MyApp());
    
        await tester.enterText(find.byKey(Key('phoneInput')), 'test');
        await tester.enterText(find.byKey(Key('passwordInput')), 'test');
        await tester.tap(find.byIcon(Icons.lock));
    
        SharedPreferences prefs = await SharedPreferences.getInstance();
        expect(prefs.getString('phone'), 'test');
        expect(prefs.getString('password'), 'test');
      });
    }
    
    
    

    Original answer:

    
    testWidgets('Click on login saves the credentials',
          (WidgetTester tester) async {
          final AutomatedTestWidgetsFlutterBinding binding = tester.binding;
          binding.addTime(const Duration(seconds: 10)); // or longer if needed
        await tester.pumpWidget(MyApp());
    
        await tester.enterText(find.byKey(Key('phoneInput')), 'test');
        await tester.enterText(find.byKey(Key('passwordInput')), 'test');
        await tester.tap(find.byIcon(Icons.lock));
    
        SharedPreferences prefs = await SharedPreferences.getInstance();
        expect(prefs.getString('phone'), 'test');
        expect(prefs.getString('password'), 'test');
      });