2

I'm trying to use widget test for my project and test works fine till reach the point I use an http request in the actual page and it ,I think, ignore the request

final account = await http.post(
                  'http://10.0.2.2:5000/LogIn',
                  headers: <String, String>{
                    'Content-Type': 'application/json; charset=UTF-8',
                  },
                  body: json.encode({'email': email, 'password': password}),
                );

the account.body returns empty while it works well during using the emulator

 testWidgets("Successful Sign In", (WidgetTester tester) async {
  await tester.pumpWidget(MaterialApp(home: SignIn()));

  //1-find widgets needed
  final textfieldemail = find.byKey(Key("emailtextformfield"));
  expect(textfieldemail, findsOneWidget);
  final textfieldpassword = find.byKey(Key("passwordtextformfield"));
  expect(textfieldpassword, findsOneWidget);
  final buttonsignin = find.byKey(Key("Signin"));
  expect(buttonsignin, findsOneWidget);

  //2-execute the actual test
  await tester.enterText(textfieldemail, "Weaam.wewe91@gmail.com");
  await tester.enterText(textfieldpassword, "Weaam@91");
  await tester.tap(buttonsignin);
  await tester.pump(Duration(seconds: 5));
  //await tester.pump(Duration(seconds: 5));
  //await _navigateToAccountHome(tester);

  //3-check results
  expect(find.byType(DeliveryHome), findsOneWidget);
});

});

I am not sure if I missed something I'm still beginner

2 Answers2

8

testWidgets by default uses a Mocked http class which will always return HTTP error 400. This is likely why your code works in emulator, but not in tests.

To get actual HTTP responses from a web server prefix/setup before your test with: HttpOverrides.global = null;

Example

Provided by dnfield (on Google Flutter team).

See full github thread

import 'dart:io';

import 'package:flutter_test/flutter_test.dart';
import 'package:http/http.dart';

void main() {
  setUpAll(() {
    // ↓ required to avoid HTTP error 400 mocked returns
    HttpOverrides.global = null;
  });
  testWidgets('http', (WidgetTester tester) async {
    await tester.runAsync(() async {
      final HttpClient client = HttpClient();
      final HttpClientRequest request =
      await client.getUrl(Uri.parse('https://google.com'));

      final HttpClientResponse response = await request.close();
      print(response.statusCode);  // Should get 200
    });
  });

  testWidgets('http2', (WidgetTester tester) async {
    await tester.runAsync(() async {
      final result = await get(Uri.parse('https://google.com'));
      print(result.statusCode); // Should get 200
    });
  });
}
Baker
  • 24,730
  • 11
  • 100
  • 106
0

You should't use http directly from widget. If so, your are merging UI with business logic as a bad practice. If both layers are not decoupled, you won't be able to mock the answers from server.

Once your code is decoupled, the mockito package will help you.

In the test, you should write something like this:

// Unstubbed methods return null.
expect(cat.sound(), nullValue);

// Stub a mock method before interacting.
when(cat.sound()).thenReturn("Purr");
expect(cat.sound(), "Purr");

// You can call it again.
expect(cat.sound(), "Purr");

// Let's change the stub.
when(cat.sound()).thenReturn("Meow");
expect(cat.sound(), "Meow");

// You can stub getters.
when(cat.lives).thenReturn(9);
expect(cat.lives, 9);

// You can stub a method to throw.
when(cat.lives).thenThrow(RangeError('Boo'));
expect(() => cat.lives, throwsRangeError);

// We can calculate a response at call time.
var responses = ["Purr", "Meow"];
when(cat.sound()).thenAnswer((_) => responses.removeAt(0));
expect(cat.sound(), "Purr");
expect(cat.sound(), "Meow");

For more details, read the package readme.

Frank Moreno
  • 304
  • 1
  • 7