Test Connectable Stream in Dart - dart

I have the following Stream:
static Stream<FirebaseUser> _onAuthStateChangedOrReloaded =
_mergeWithOnUserReloaded(_auth.onAuthStateChanged);
static Stream<FirebaseUser> _mergeWithOnUserReloaded(Stream<FirebaseUser> stream) {
return Rx.merge([stream, onUserReloaded]).publishValue()..connect();
}
publishValue()..connect() make it a Connectable Stream, but I am having trouble trying to test it.
This is my old test, from before I made that stream a Connectable Stream:
test('Reloads emits the new User in onAuthStateChangedOrReloaded', () async {
expect(FirebaseUserReloader.onAuthStateChangedOrReloaded,
emitsInOrder([mockOldUser, mockNewUser]));
await FirebaseUserReloader.reloadCurrentUser();
});
But this test doesn't work with Connectable Streams, as test uses a StreamQueue and it needs to call pause on the stream, I get this error if I try:
dart:core Object.noSuchMethod
package:async/src/stream_queue.dart 472:19 StreamQueue._pause
package:async/src/stream_queue.dart 434:7 StreamQueue._updateRequests
package:async/src/stream_queue.dart 514:5 StreamQueue._addResult
package:async/src/stream_queue.dart 484:9 StreamQueue._ensureListening.<fn>
dart:async _EventSinkWrapper.add
package:rxdart/src/transformers/start_with.dart 18:17 _StartWithStreamSink.add
dart:async _StreamSinkWrapper.add
package:rxdart/src/transformers/start_with.dart 59:13 _StartWithStreamSink._safeAddFirstEvent
package:rxdart/src/transformers/start_with.dart 40:13 _StartWithStreamSink.onListen
package:rxdart/src/utils/forwarding_stream.dart 18:22 forwardStream.<fn>
dart:async _BoundSinkStream.listen
package:rxdart/src/streams/defer.dart 37:18 DeferStream.listen
dart:async StreamView.listen
package:async/src/stream_queue.dart 483:31 StreamQueue._ensureListening
package:async/src/stream_queue.dart 542:7 StreamQueue._addRequest
package:async/src/stream_queue.dart 299:5 StreamQueue.startTransaction
package:test_api expect
package:flutter_test/src/widget_tester.dart 234:3 expect
test\firebase_user_stream_test.dart 70:7 main.<fn>.<fn>
===== asynchronous gap ===========================
dart:async _BoundSinkStream.listen
package:rxdart/src/streams/defer.dart 37:18 DeferStream.listen
dart:async StreamView.listen
package:async/src/stream_queue.dart 483:31 StreamQueue._ensureListening
package:async/src/stream_queue.dart 542:7 StreamQueue._addRequest
package:async/src/stream_queue.dart 299:5 StreamQueue.startTransaction
package:test_api expect
package:flutter_test/src/widget_tester.dart 234:3 expect
test\firebase_user_stream_test.dart 70:7 main.<fn>.<fn>
NoSuchMethodError: The method 'pause' was called on null.
Receiver: null
Tried calling: pause()
I was advised to use expectAsync1, but I can't make it work with emitsInOrder.
How can I test a Connectable Stream with emitsInOrder?

Related

Dart Higher-Order function with Generics

I'm trying to create a simple debug/print function that I can pipe through a sequence of then while processing Future results in Dart.
My function definition is as follows:
import 'dart:async';
typedef FutureOr<T> Pipe<T>(T pipeThrough);
Pipe<A> debug<A>(String log) {
return (A pipeThrough) {
print(log);
return pipeThrough;
};
}
It will return a function that just pipes through whatever it has received from the Future chain, and before that it will print the message log that has been sent to debug.
The way I'm using the function is quite simple:
Future<Map> load(String folder) {
return File(Paths.of([folder, 'data.json']))
.readAsString()
.then((s) => jsonDecode(s))
.then(debug<Map>('JSON LOADED!'));
}
As you can see in the last then in the future chain, it is supposed to return whatever was in the chain, but before that print 'JSON LOADED!'.
But there is something with the generics and Future api that I didn't manage to find a way to make it work, here's the error:
Unhandled exception:
type '(Map<dynamic, dynamic>) => Map<dynamic, dynamic>' is not a subtype of type '(dynamic) => FutureOr<Map<dynamic, dynamic>>'
#0 load (file:///{.../..../......}/data/data_json.dart:11:13)
#1 main (file:///{.../..../......}/data/main.dart:7:28)
#2 _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:301:19)
#3 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:168:12)
I've tried a bunch of different things, but fundamentally I don't get what's happening, doesn't dart infer the proper types based on the generic types annotation?
I don't know why it can't handle the type here, but changing the code to
Future<Map> load(String folder) {
return File(Paths.of([folder, 'data.json']))
.readAsString()
.then((s) => jsonDecode(s))
.then((v) => debug<Map>('JSON LOADED!')(v));
}
fixes your issue. I had thought that this should be equivalent...

"Bad state: Future already completed" in Aqueduct

I'm attempting to, in the prepare method of the main channel, load up an AutoRefreshingAuthClient and subsequently a FirestoreAPI object, but I am getting the following stack trace:
Unhandled exception:
Bad state: Future already completed
#0 _Completer.completeError (dart:async/future_impl.dart:21:31)
#1 ApplicationIsolateSupervisor._handleIsolateException (package:aqueduct/src/application/isolate_supervisor.dart:129:24)
#2 ApplicationIsolateSupervisor.listener (package:aqueduct/src/application/isolate_supervisor.dart:102:7)
#3 _RootZone.runUnaryGuarded (dart:async/zone.dart:1314:10)
#4 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:336:11)
#5 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:263:7)
#6 _SyncStreamController._sendData (dart:async/stream_controller.dart:764:19)
#7 _StreamController._add (dart:async/stream_controller.dart:640:7)#8 _StreamController.add (dart:async/stream_controller.dart:586:5)
#9 _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:171:12)
Though this stack trace does not point to anything in my code, I isolated the issue to an awaited clientViaServiceAccount call (code below) in the prepare method.
I'm unsure as to what I'm doing wrong as the documentation for this API (googleapis) is largely unhelpful in this context, and the example method shown in the documentation doesn't seem to work here.
How do I properly set up the AutoRefreshingAuthClient and FirestoreAPI objects without getting this exception?
This is an Aqueduct project that has no issues running if I simply run the example code shipped with the project at creation.
I've tried shifting the calls and initialization to different scopes, but aside from that I don't know what to try.
channel.dart
import 'dart:io';
import 'package:googleapis/firestore/v1.dart';
import 'package:googleapis_auth/auth.dart';
import 'package:googleapis_auth/auth_io.dart';
import 'package:mm_block/mm_block.dart';
import 'package:mm_block/controller/member.dart';
final _credentials = ServiceAccountCredentials.fromJson(
File('credentials').readAsString()
);
final _scopes = [
FirestoreApi.CloudPlatformScope
];
class MMBlockChannel extends ApplicationChannel {
FirestoreApi firestore;
#override
Future prepare() async {
// The issue is here.
await clientViaServiceAccount(_credentials, _scopes)
.then((client) => firestore = FirestoreApi(client));
}
...
}
This should all run correctly and I should end up with an AutoRefreshingAuthClient being passed to the FirestoreAPI call.

How to parse json data if it has escape characters in response with dart or flutter?

my json response is {"quoteText":"You\'re not obligated to win. You\'re obligated to keep trying to do the best you can every day.", "quoteAuthor":"Marian Edelman"} and I am trying to decode by Map<String, dynamic> quoteData = jsonDecode(response.body); but getting this exception
[ERROR:flutter/shell/common/shell.cc(184)] Dart Error: Unhandled exception:
E/flutter ( 5814): FormatException: Unrecognized string escape (at character 20)
E/flutter ( 5814): {"quoteText":"You\'re not obligated to win. You\'re obligated to keep tryin...
E/flutter ( 5814): ^
E/flutter ( 5814):
E/flutter ( 5814): #0 _ChunkedJsonParser.fail (dart:convert/runtime/libconvert_patch.dart:1358:5)
Tried by json.decode() and by doing flutter-remove-escape-sequence-in-dart but no luck. Any workaround?
That isn't valid json. Single quotes should not be escaped. Either you should get the source to fix it, or you can try to fix the string yourself by wholesale replacing any occurrence of \' with '.
String fixed = badString.replaceAll(r"\'", "'");
json.decode(fixed);

Navigate to other page

I use a Datepicker Cupertiono in my Flutter application:
https://github.com/wuzhendev/flutter-cupertino-date-picker
There is a method named "onConfirm()" where I'm trying to redirect user to other page, but with no luck.
I tried
return Navigator.pushReplacementNamed(ctx, '/otherPage');
but what actually happens when this return statment is hit, is cupertino widget closes and nothing happen. There is no error
When I try to use :
return Navigator.pushNamed<bool>(
ctx,
'/route/' + object.id.toString());
Some errors apear:
Performing hot restart...
Restarted application in 1 685ms.
I/flutter (20542): 112
E/flutter (20542): [ERROR:flutter/shell/common/shell.cc(188)] Dart Error: Unhandled exception:
E/flutter (20542): Looking up a deactivated widget's ancestor is unsafe.
E/flutter (20542): At this point the state of the widget's element tree is no longer stable. To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling
inheritFromWidgetOfExactType() in the widget's didChangeDependencies() method.
E/flutter (20542):
E/flutter (20542): #0 Element._debugCheckStateIsActiveForAncestorLookup.<anonymous closure> (package:flutter/src/widgets/framework.dart:3232:9)
E/flutter (20542): #1 Element._debugCheckStateIsActiveForAncestorLookup (package:flutter/src/widgets/framework.dart:3241:6)
E/flutter (20542): #2 Element.ancestorStateOfType (package:flutter/src/widgets/framework.dart:3289:12)
E/flutter (20542): #3 Scaffold.of (package:flutter/src/material/scaffold.dart:935:42)
You should use Navigator.push.
Import your page, example: import './otherPage.dart';
Than change your line
return Navigator.pushReplacementNamed(ctx, '/otherPage');
To
return Navigator.push(context, 'otherClassName');

How do you listen for custom events in Polymer Dart 1.0?

I've been trying to do something like the following inside a Polymer Dart 1.0 element
#PolymerRegister('some-element')
class SomeElement extends PolymerElement {
...
void fireEvent() {
fire('someevent');
}
...
}
I then listen for it in this manner
<some-element on-someevent="handleSomeEvent"></some-element>
with the method defined inside the Polymer Element that I'm using in defined thus
#reflectable
void handleSomeEvent([_, __]) {
...
}
The problem is I get an
Unhandled exception
which wasn't helpful, and it took me a while to figure out that the above was causing it. If I remove the
#reflectable
annotation from the event handler method, I get the following
method `registered` not defined
I was wondering if there is a special way to handle custom events in Polymer Dart 1.0?
I can handle it this way
on['someevent'].listen(handleSomeEvent);
which does work, it's just I don't see why I shouldn't be able to handle it both ways. I'm thinking I'll be submitting a bug report on this, but I thought I'd put it here and check to see if I've done this correctly, since what I did, apart from using
#reflectable
which is Polymer Dart 1.0 specific, is what they say you should do in Polymer JS whose documentation can be found here
UPDATE
I should clarify, this exception happened at load time, when the element was being registered. I'll put the full exception in later, when I have a bit more time.
The exception I'm getting is the following
Exception: Uncaught Error: Unhandled exception:
Reflecting on un-marked type 'JsObjectImpl'
#0 _InstanceMirrorImpl._InstanceMirrorImpl (package:reflectable/src/reflectable_transformer_based.dart:150:9)
#1 ReflectableImpl.reflect (package:reflectable/src/reflectable_transformer_based.dart:1216:16)
#2 _setupReflectableMethods.<anonymous closure>.<anonymous closure> (package:polymer/src/common/polymer_descriptor.dart:151:49)
#3 JsObject._callMethod (dart:js:678)
#4 JsObject.callMethod (dart:js:618)
#5 PolymerRegister.initialize (package:polymer/src/common/polymer_register.dart:19:13)
#6 loadInitializers.<anonymous closure>.<anonymous closure> (package:initialize/src/static_loader.dart:46:32)
#7 _runInitQueue (package:initialize/initialize.dart:35:24)
#8 _runInitQueue.<anonymous closure> (package:initialize/initialize.dart:38:26)
#9 _RootZone.runUnary (dart:async/zone.dart:1165)
#10 _Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:502)
#11 _Future._propagateToListeners (dart:async/future_impl.dart:585)
#12 _Future._completeWithValue (dart:async/future_impl.dart:376)
#13 _Future._asyncComplete.<anonymous closure> (dart:async/future_impl.dart:430)
#14 _microtaskLoop (dart:async/schedule_microtask.dart:43)
#15 _microtaskLoopEntry (dart:async/schedule_microtask.dart:52)
#16 _ScheduleImmediateHelper._handleMutation (dart:html:42565)
Stack Trace:
#0 JsObject._callMethod (dart:js:678)
#1 JsObject.callMethod (dart:js:618)
#2 PolymerRegister.initialize (package:polymer/src/common/polymer_register.dart:19:13)
#3 loadInitializers.<anonymous closure>.<anonymous closure> (package:initialize/src/static_loader.dart:46:32)
#4 _runInitQueue (package:initialize/initialize.dart:35:24)
#5 _runInitQueue.<anonymous closure> (package:initialize/initialize.dart:38:26)
#6 _RootZone.runUnary (dart:async/zone.dart:1165)
#7 _Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:502)
#8 _Future._propagateToListeners (dart:async/future_impl.dart:585)
#9 _Future._completeWithValue (dart:async/future_impl.dart:376)
#10 _Future._asyncComplete.<anonymous closure> (dart:async/future_impl.dart:430)
#11 _microtaskLoop (dart:async/schedule_microtask.dart:43)
#12 _microtaskLoopEntry (dart:async/schedule_microtask.dart:52)
#13 _ScheduleImmediateHelper._handleMutation (dart:html:42565)
Further Info
Next time I ask for help, I'll just use the exact code I'm using. The method I'm annotating with
#reflectable
is called registered.
#reflectable
void registered([_, __]) {
....
}
If I change the name of this method to something else like
#reflectable
void someOtherName([_, __]) {
...
}
The exception doesn't occur. Sorry about that, it didn't occur to me the name of the method might have something to do with it. Again sorry, but I still would like some explanation as to why the name of the annotated method matters in this case.
This is just fine.
#reflectable
void handleSomeEvent([_, __]) {
...
}
Can you provide the project in a GitHub repo that allows to reproduce the problem?
An additional method would be
#Listen('someevent')
void handleSomeEvent([_, __]) {
...
}
(You don't need to add anything to HTML for this method).

Resources