felangel / mocktail

A mock library for Dart inspired by mockito
https://pub.dev/packages/mocktail
MIT License
624 stars 81 forks source link

Cannot distinguish 2 sequential action dispatch calls #122

Open ch-angelino opened 2 years ago

ch-angelino commented 2 years ago

Describe the bug When verifying that 2 actions have been dispatched from a redux store in a redux middleware one after the other, the verify function cannot distinguish the 2 actions, i.e. any of the 2 actions will match 2 calls instead of 1 each.

To Reproduce lib/middleware.dart:

import 'package:equatable/equatable.dart';
import 'package:meta/meta.dart';
import 'package:redux/redux.dart';

List<Middleware<AppState>> getHomeMiddleware() => [
      HomeMiddleware().getMiddlewareBindings(),
    ].expand((x) => x).toList();

class HomeMiddleware {
  List<Middleware<AppState>> getMiddlewareBindings() => [
        TypedMiddleware<AppState, TriggerAction>(_handleTriggerAction),
      ];

  void _handleTriggerAction(Store<AppState> store, TriggerAction action, next) {
    next(action);

    store.dispatch(DispatchedA());
    store.dispatch(DispatchedB());
  }
}

@immutable
class TriggerAction {
  @override
  String toString() {
    return 'TriggerAction{}';
  }
}

@immutable
class DispatchedA {
  @override
  String toString() {
    return 'DispatchedA{}';
  }
}

@immutable
class DispatchedB {
  @override
  String toString() {
    return 'DispatchedB{}';
  }
}

class AppState extends Equatable {
  @override
  List<Object> get props => [];
}

test/middleware_test.dart:

import 'package:flutter_test/flutter_test.dart';
import 'package:demo/middleware.dart';
import 'package:mocktail/mocktail.dart';
import 'package:redux/redux.dart';

void main() {
  setUpAll(() {
    registerFallbackValue(TriggerAction());
    registerFallbackValue(DispatchedA());
    registerFallbackValue(DispatchedB());
  });

  test('This is the test that fails', () async {
    final store = StoreMock();

    await getHomeMiddleware().call(store, TriggerAction());

    verify(() => store.dispatch(any<DispatchedA>()));
    verify(() => store.dispatch(any<DispatchedB>()));
  });
}

class StoreMock extends Mock implements Store<AppState> {}

extension MiddlewareExtension on List<Middleware<AppState>> {
  Future<void> call(Store<AppState> store, dynamic action) async {
    for (final middleware in this) {
      await middleware.call(store, action, (_) {});
    }
  }
}

Steps to reproduce the behavior:

  1. Run flutter test
  2. See error

Expected behavior Test passes.

Logs

package:test_api                           fail
package:mocktail/src/mocktail.dart 722:7   _VerifyCall._checkWith
package:mocktail/src/mocktail.dart 515:18  _makeVerify.<fn>
test/middleware_test.dart 19:11            main.<fn>

No matching calls. All calls: [VERIFIED] StoreMock.dispatch(DispatchedA{}), [VERIFIED] StoreMock.dispatch(DispatchedB{})
(If you called `verify(...).called(0);`, please instead use `verifyNever(...);`.)

Additional context Tested on Mocktail versions 0.2.0 and 0.3.0.

Commenting out any of the 2 verify checks makes the test pass, so the checks both work on their own. Adding .called(2) to any of the 2 verify checks and commenting out the other check makes the test pass, so it seems there is no distinction between the 2 different actions.

felangel commented 2 years ago

Hi @ch-angelino πŸ‘‹ 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 could clone a working reproduction sample and run/debug it locally, thanks! πŸ™

ch-angelino commented 2 years ago

Hi @felangel πŸ‘‹

Here you go: https://github.com/ch-angelino/Flutter-Mocktail-Bug-Demo-122

Just clone the repo then go flutter pub get and flutter test and the error should come up 🀞

Thanks for looking into this πŸ™

felangel commented 2 years ago

Hi @felangel πŸ‘‹

Here you go: https://github.com/ch-angelino/Flutter-Mocktail-Bug-Demo-122

Just clone the repo then go flutter pub get and flutter test and the error should come up 🀞

Thanks for looking into this πŸ™

Thanks I’ll take a look tomorrow morning!

ch-angelino commented 2 years ago

Hey @felangel, any update on this? TIA

felangel commented 6 months ago

Hi @ch-angelino is this still an issue? I'm really sorry I didn't have time to look and it fell off my radar :(

ch-angelino commented 5 months ago

@felangel I just tested that repro repo on Mocktail 1.0.3 and Flutter 3.13.9 and the same error is still coming up:

% flutter test   
00:05 +0 -1: Fail 1 [E]                                                                                                                
  No matching calls. All calls: [VERIFIED] StoreMock.dispatch(DispatchedA{}), [VERIFIED] StoreMock.dispatch(DispatchedB{})
  (If you called `verify(...).called(0);`, please instead use `verifyNever(...);`.)
  package:matcher                            fail
  package:mocktail/src/mocktail.dart 728:7   _VerifyCall._checkWith
  package:mocktail/src/mocktail.dart 519:18  _makeVerify.<fn>
  test/middleware_test.dart 19:11            main.<fn>