Skip to content

Rill Matchers

ribs_test provides async matchers that run a Rill to completion and assert on what it emits and how it finishes — whether that's success, an error, or cancelation.

dart
import 'package:ribs_test/ribs_rill_test.dart';

All matchers extend AsyncMatcher and work directly with expect / expectLater. Pass a Rill<A> as the actual value; the matcher drives it to completion internally.


Success matchers

producesInOrder(expected)

Asserts the Rill succeeds and emits elements in exactly the given order. expected may be a Dart Iterable or any RIterableOnce.

dart
void producesInOrderTests() {
  test('emits expected sequence', () {
    expect(Rill.emits([1, 2, 3]), producesInOrder([1, 2, 3]));
    expect(Rill.emits([1, 2, 3]).map((n) => n * 2), producesInOrder([2, 4, 6]));

    // IList is also accepted by the matcher
    expect(Rill.emits([10, 20]), producesInOrder(ilist([10, 20])));
  });
}

The test fails if the Rill emits a different sequence, errors, or is canceled.

producesOnly(value)

Shorthand for producesInOrder([value]). Asserts the Rill emits exactly one element equal to value.

dart
void producesOnlyTests() {
  test('emits exactly one element', () {
    expect(Rill.emit(42), producesOnly(42));
  });
}

producesUnordered(expected)

Asserts the Rill succeeds and emits the same multiset of elements as expected, regardless of order. Useful for parallel or non-deterministically ordered streams.

dart
void producesUnorderedTests() {
  test('emits the same elements in any order', () {
    expect(Rill.emits([3, 1, 2]), producesUnordered([1, 2, 3]));
  });

  test('checking merged rills', () {
    expect(
      Rill.emits([1, 2, 3]).merge(Rill.emits([4, 5, 6])),
      producesUnordered([1, 2, 3, 4, 5, 6]),
    );
  });
}

producesNothing()

Asserts the Rill succeeds without emitting any elements.

dart
void producesNothingTests() {
  test('emits no elements', () {
    expect(Rill.empty<int>(), producesNothing());
    expect(Rill.emits([1]).filter((_) => false), producesNothing());
  });
}

Error matcher

producesError([matcher])

Asserts the Rill fails with an error. Pass a nested matcher to validate the specific error value.

dart
void producesErrorTests() {
  test('fails with error', () {
    expect(Rill.raiseError<int>('oops'), producesError('oops'));
    expect(Rill.raiseError<int>(Exception('!')), producesError(isA<Exception>()));
    expect(Rill.raiseError<int>('fatal'), producesError()); // any error
  });
}

Comparison matcher

producesSameAs(expected)

Runs both rills to completion and asserts they have the same outcome and the same emitted elements. Covers all three outcome types: success (same elements), error (same error), and cancelation.

This is most useful when testing transformations that should preserve a rill's contents exactly — for example, custom pipes or codec round-trips:

dart
void producesSameAsTests() {
  test('identity transformation preserves contents', () {
    final source = Rill.emits([1, 2, 3]);
    expect(source.map((n) => n), producesSameAs(Rill.emits([1, 2, 3])));
  });

  test('error comparison', () {
    expect(
      Rill.raiseError<int>('oops'),
      producesSameAs(Rill.raiseError<int>('oops')),
    );
  });

  test('codec round-trip', () {
    Rill<A> roundTrip<A>(Rill<A> source) => source;

    expect(roundTrip(Rill.emits([1, 2, 3])), producesSameAs(Rill.emits([1, 2, 3])));
  });
}

Summary

MatcherAsserts
producesInOrder(xs)Succeeds, emits xs in order
producesOnly(x)Succeeds, emits exactly one element x
producesUnordered(xs)Succeeds, emits the same elements as xs in any order
producesNothing()Succeeds, emits no elements
producesError([m])Fails with an error matching m
producesSameAs(rill)Same outcome and same elements as rill