A month of Flutter: Stream transforms and failing tests

Abraham Williams - Dec 13 '18 - - Dev Community

Originally published on bendyworks.com.

Now that I've got a Post model with mock data and a StreamBuilder for rendering, it all needs to be wired together.

The main changes I'm making are in _MyHomePageState where I'm replacing the stream of ints with a call to the new _loadPosts method.

Stream<List<Post>> _loadPosts(BuildContext context) {
  return DefaultAssetBundle.of(context)
      .loadString('assets/posts.json')
      .then<List<dynamic>>((String value) => json.decode(value))
      .asStream()
      .map(_convertToPosts);
}
~~~{% endraw %}

{% raw %}`_loadPosts`{% endraw %} uses [{% raw %}`DefaultAssetBundle.of`{% endraw %}](https://docs.flutter.io/flutter/widgets/DefaultAssetBundle/of.html) to get the most appropriate [{% raw %}`AssetBundle`](https://docs.flutter.io/flutter/services/AssetBundle-class.html) for loading files from the `assets` directory.

Reading the {% raw %}`String`{% endraw %} contents of a file is asynchronous, after which the JSON contents can be decoded. The loading and decoding will happen as a {% raw %}`Future`{% endraw %} but I want to be working on a stream so I'll use [`asStream`](https://api.dartlang.org/stable/2.1.0/dart-async/Future/asStream.html) to convert the `Future` to a `Stream`.

Finally the Stream will then get transformed using [`map`](https://api.dartlang.org/stable/2.1.0/dart-async/Stream/map.html) and another new method `_convertToPosts`.

~~~dart
List<Post> _convertToPosts(List<dynamic> data) {
  return data.map((dynamic item) => Post.fromMap(item)).toList();
}
~~~

Every time an event comes down the stream, `map` will call the convert method on the value. In this case the value is a `List` of items and `List`'s [{% raw %}`map`{% endraw %}](https://api.dartlang.org/stable/2.1.0/dart-core/Iterable/map.html) will pass each item to `Post.fromMap`. Note that `map` on a `List` is different from `map` on a `Stream`. `map` on a `List` is lazy so we'll force it to execute with a final [`toList`](https://api.dartlang.org/stable/2.1.0/dart-core/Iterable/toList.html).

The rest of the changes are going thought the code base and updating {% raw %}`List<int>`{% endraw %} types to be {% raw %}`List<Post>`{% endraw %} types and passing {% raw %}`Post`{% endraw %} instances into the rendering {% raw %}`PostItem`{% endraw %}s. I'll also replace the hard coded `'Prim Birb'` text with the dynamic `username` from the `Post` instances.

![Screenshot of rendered mock usernames](https://thepracticaldev.s3.amazonaws.com/i/lmfoehbinrds1zn7kvaw.png)

As I was updating the tests to use the new mock JSON data, I kept running into failures. I was seeing tests timing out or the `PostsList` error handling showing errors instead of content. After some digging it turns out that the code in `testWidgets` [can't access](https://github.com/flutter/flutter/issues/8490) files or assets. With [CI configured](https://bendyworks.com/blog/a-month-of-flutter-configuring-continuous-integration) I can't merge code without passing tests so come back tomorrow to see how I fix them.

## Code changes

- [#29 Turn mock posts into Stream](https://github.com/abraham/birb/pull/29)
Enter fullscreen mode Exit fullscreen mode
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .