Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 725
Jorge Alberto Díaz Orozco Avatar asked Jan 14 '19 20:01

Jorge Alberto Díaz Orozco


2 Answers

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');
  });

like image 104
TruongSinh Avatar answered Oct 20 '22 18:10

TruongSinh


You could use the provided mock setMockInitialValues

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

    await tester.pumpWidget(MyApp());

    SharedPreferences.setMockInitialValues(<String, dynamic>{
      'flutter.phone': '',
      'flutter.password': '',
    });

    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');
  });
like image 34
Terry Avatar answered Oct 20 '22 17:10

Terry