Is there any convenient way to assert all the items emitted by a Stream
in order until it is canceled?
If I use:
expectLater(
stream,
emitsInOrder(<String>[
'item1',
'item2',
]),
);
and the Stream
emits ['item1', 'item2', 'item3']
, the test won't fail.
The only way I've found so far is the following:
var count = 0;
final expected = ['item1', 'item2', 'item3'];
stream.listen(
expectAsync1(
(final result) {
expect(result, expected[count ]);
},
count: expected.length,
),
);
But it is a bit verbose and not very easy to read. Is there a simpler/more elegant way?
CodePudding user response:
You can collect the items into a list, using toList
, then compare it to your own expectation list:
await expectLater(stream.toList(), completion(expected));
This does not handle the case where the stream doesn't close at all (but then, nothing does, you just have to wait for a timeout).
It doesn't catch errors until all events have been emitted, the emitsInOrder
approach is better for that. Not shorter, though.
CodePudding user response:
emitsDone
can be used if the Stream
is closed at some point.
E.g:
test('Test', () async {
final controller = StreamController<String>();
final stream = controller.stream;
final matcher = expectLater(
stream,
emitsInOrder(<dynamic>[
'Item1',
'Item2',
emitsDone,
]),
);
controller
..add('Item1')
..add('Item2')
..add('Item3')
..close();
await matcher;
await controller.close();
});
The test fails with error:
Expected: should do the following in order:
• emit an event that 'Item1'
• emit an event that 'Item2'
• be done
Actual: <Instance of '_ControllerStream<String>'>
Which: emitted • Item1
• Item2
• Item3
x Stream closed.
which didn't be done
As @Irn suggest, a more compact alternative for Stream
s that complete at some point is using toList
:
test('Test', () async {
final controller = StreamController<String>();
final stream = controller.stream;
final matcher = expectLater(stream.toList(), completion(<String>['Item1', 'Item2']));
controller
..add('Item1')
..add('Item2')
..add('Item3')
..close();
await matcher;
await controller.close();
});
If the Stream
is never closed, you can add a timeout and check the items that have been emitted in that period:
test('Test3', () async {
final controller = StreamController<String>();
final stream = controller.stream.timeout(const Duration(milliseconds: 200));
final matcher = expectLater(
stream,
emitsInOrder(<dynamic>[
'Item1',
'Item2',
]),
);
controller
..add('Item1')
..add('Item2');
await matcher;
await controller.close();
});