Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to mock with await for ? #108

Closed
woprandi opened this issue Jan 27, 2022 · 8 comments
Closed

How to mock with await for ? #108

woprandi opened this issue Jan 27, 2022 · 8 comments
Assignees
Labels
question Further information is requested

Comments

@woprandi
Copy link

I have this kind of code

void main() {
  runApp(Provider(
    create: (_) => Repo(),
    child: MyApp(),
  ));
}

class MyApp extends StatefulWidget {
  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  WebSocket? _ws;
  var value = "";
  Timer? _timer;

  void _connect() async {
    try {
      print("connecting...");
      _ws = await context.read<Repo>().websocket.timeout(Duration(seconds: 10));
      print("connected");

        await for (var s in _ws!) {
        setState(() {
          value = s;
        });
      }
    } finally {
      print("disconnected");
      _timer = Timer(Duration(seconds: 10),  _connect);
    }
  }

  @override
  void initState() {
    _connect();
    super.initState();
  }

  @override
  void dispose() {
    _timer?.cancel();
    _ws?.close();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Text(value),
      ),
    );
  }
}

class Repo {
  Future<WebSocket> get websocket => WebSocket.connect('ws://...');
}

This code works.
I would like to test the automatic reconnection when websocket connection is closed (with mocktail to mock). I discovered that stream.listen(...) is called under the hood when using await for syntax. But I'm unable to get out of the loop during test. This is what I tried.

import 'dart:async';
import 'dart:io';

import 'package:flutter_playground/main.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:provider/provider.dart';

class MockWS extends Mock implements WebSocket {}

class MockRepo extends Mock implements Repo {}

void main() {
  testWidgets('auto reconnect', (WidgetTester tester) async {
    final ws = MockWS();
    final repo = MockRepo();
    final ctrl = StreamController();
    when(() => repo.websocket).thenAnswer((_) async => ws);
    when(() => ws.listen(
          any(),
          onDone: any(named: 'onDone'),
          onError: any(named: 'onError'),
          cancelOnError: any(named: 'cancelOnError'),
        )).thenAnswer((invocation) {
      return ctrl.stream.listen(
        invocation.positionalArguments[0],
        onDone: invocation.namedArguments['onDone'],
        onError: invocation.namedArguments['onError'],
        cancelOnError: invocation.namedArguments['cancelOnError'],
      );
    });
    when(() => ws.close()).thenAnswer((invocation) async => null);
    await tester.pumpWidget(Provider<Repo>.value(
      value: repo,
      child: MyApp(),
    ));

    // Try to close the stream
    await ctrl.close();
    await tester.pump(Duration(seconds: 10));
    verify(() => repo.websocket).called(2);
  });
}

But the test fails, it does not get out the await for loop. How to emulate a loop exit ?
I didn't get any answer on SA so maybe I'll get a fast answer here.

@felangel felangel added the question Further information is requested label Mar 1, 2022
@felangel
Copy link
Owner

felangel commented Mar 1, 2022

Hi @woprandi 👋
Thanks for opening an issue!

Are you able to provide a link to a minimal reproduction sample? It would be much easier to help if I'm able to run/debug the issue locally, thanks! 🙏

@felangel felangel self-assigned this Mar 1, 2022
@felangel felangel added the waiting for response Waiting for follow up label Mar 1, 2022
@woprandi
Copy link
Author

woprandi commented Mar 1, 2022

@felangel well, what's the problem with the code I posted ?

@felangel
Copy link
Owner

felangel commented Mar 1, 2022

It's not clear what versions of dependencies you're using are and what environment you're running in. It would be much easier to help if you could provide a link to a GitHub repo that I could clone and run to reproduce the issue.

I can try to put together an example based on the snippets you provided but it's always much easier and less time consuming to investigate when there is a minimal reproduction sample that can quickly be cloned/run.

@woprandi
Copy link
Author

woprandi commented Mar 2, 2022

OK you can clone here https://github.com/woprandi/flutter_playground
You will need a websocket server to simulate (re)connections. You can use the test.py file (pip install websockets also).
As you can see, the code works as expected but not the test

@woprandi
Copy link
Author

@felangel Were you able to take a look ?

@felangel felangel removed the waiting for response Waiting for follow up label Apr 1, 2022
@felangel
Copy link
Owner

@woprandi is this still an issue? This fell off my radar, apologies :(

@felangel felangel added the waiting for response Waiting for follow up label Apr 20, 2024
@woprandi
Copy link
Author

@felangel No problem I didn't remember about this issue. I don't know if it's still relevant. I'd need to take 5 min to retry

@felangel
Copy link
Owner

Closing for now since this issue is quite old and there isn't a minimal reproduction sample. If this is still a problem please file a new issue with a link to a reproduction sample, thanks!

@felangel felangel removed the waiting for response Waiting for follow up label Jun 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants