Skip to content

Commit

Permalink
Don't trigger unneeded ActionSpyEvent for AsyncAction (mobxjs#784)
Browse files Browse the repository at this point in the history
* Fix for mobxjs#734

* Update async_action.dart

* spy_test.dart: ensure that spy-event is raised only once for async actions that involve scheduleMicrotask

* Updated changelog

* Updated mobx version

* Removed unneeded newline

* Removed unneeded newline

Co-authored-by: Pavan Podila <[email protected]>
  • Loading branch information
2 people authored and tlvenn committed Dec 31, 2022
1 parent 294e988 commit 5609c64
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 17 deletions.
4 changes: 4 additions & 0 deletions mobx/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2.0.7+3

- Fixed unnecessary ActionSpyEvents being triggered for AsyncAction

## 2.0.7+1 - 2.0.7+2

- Package upgrades
Expand Down
2 changes: 1 addition & 1 deletion mobx/lib/mobx.dart
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,4 @@ export 'package:mobx/src/core.dart'
export 'package:mobx/src/core/atom_extensions.dart';

/// The current version as per `pubspec.yaml`
const version = '2.0.7+2';
const version = '2.0.7+3';
21 changes: 6 additions & 15 deletions mobx/lib/src/api/async/async_action.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class AsyncAction {
}

Future<R> run<R>(Future<R> Function() body) async {
final actionInfo = _actions.startAction(name: _actions.name);
try {
return await _zone.run(body);
} finally {
Expand All @@ -32,33 +33,23 @@ class AsyncAction {
// Needed to make sure that all mobx state changes are
// applied after `await run()` completes, not sure why.
await Future.microtask(_noOp);
_actions.endAction(actionInfo);
}
}

static dynamic _noOp() => null;

R _run<R>(Zone self, ZoneDelegate parent, Zone zone, R Function() f) {
final actionInfo = _actions.startAction(name: '${_actions.name}(Zone.run)');
try {
final result = parent.run(zone, f);
return result;
} finally {
_actions.endAction(actionInfo);
}
final result = parent.run(zone, f);
return result;
}

// Will be invoked for a catch clause that has a single argument: exception or
// when a result is produced
R _runUnary<R, A>(
Zone self, ZoneDelegate parent, Zone zone, R Function(A a) f, A a) {
final actionInfo =
_actions.startAction(name: '${_actions.name}(Zone.runUnary)');
try {
final result = parent.runUnary(zone, f, a);
return result;
} finally {
_actions.endAction(actionInfo);
}
final result = parent.runUnary(zone, f, a);
return result;
}

// Will be invoked for a catch clause that has two arguments: exception and stacktrace
Expand Down
2 changes: 1 addition & 1 deletion mobx/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: mobx
version: 2.0.7+2
version: 2.0.7+3
description: "MobX is a library for reactively managing the state of your applications. Use the power of observables, actions, and reactions to supercharge your Dart and Flutter apps."

homepage: https://github.com/mobxjs/mobx.dart
Expand Down
37 changes: 37 additions & 0 deletions mobx/test/spy_test.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:async';

import 'package:mobx/mobx.dart';
import 'package:test/test.dart';

Expand Down Expand Up @@ -124,6 +126,41 @@ void main() {
d();
});

test('spy-event is raised only once when an AsyncAction is executed',
() async {
var eventCount = 0;
var endEventCount = 0;
final d = mainContext.spy((event) {
if (event is ActionSpyEvent) {
eventCount += 1;
}

if (event is EndedSpyEvent && event.type == 'action') {
endEventCount += 1;
}
});

final actionCompleter = Completer();
final microtaskCompleter = Completer();
AsyncAction('test').run(() async {
scheduleMicrotask(() {
microtaskCompleter.complete();
});
actionCompleter.complete();
});
await actionCompleter.future;
await microtaskCompleter.future;

// This is needed to ensure that all spy callbacks are executed
// before moving on to `expect`s.
await Future.value();

expect(eventCount, 1);
expect(endEventCount, 1);

d();
});

test('spy-event is raised when a Reaction is executed', () {
final o = Observable(0);
final d1 = reaction((_) => o.value, (_) {}, name: 'test');
Expand Down

0 comments on commit 5609c64

Please sign in to comment.