Skip to content

test(llc): migrate the stream_chat test suite to the stream_chat_test algebra - #2954

Draft
VelikovPetar wants to merge 100 commits into
masterfrom
test/migrate-llc-tests-to-algebra
Draft

VelikovPetar wants to merge 100 commits into
masterfrom
test/migrate-llc-tests-to-algebra

Conversation

@VelikovPetar

@VelikovPetar VelikovPetar commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Important

Depends on #2950 (test(repo): add \stream_chat_test` package). This branch is built on feat/stream-chat-test-package, so the diff below carries that package (4 files, ~1.9k lines) in addition to the migration. Merge #2950 first — once it lands, this diff reduces to the migration alone. Both branches carry the latest master`.

Rewrites the stream_chat test suite on top of the chatClientTest / channelTest
harness from #2950, and deletes the three monolithic test files it replaces.

What changes

  • channel_client_state_test.dart (164 tests) → 21 files under test/src/client/channel/state/
  • channel_test.dart (186 tests) → 28 files under test/src/client/channel/
  • client_test.dart (~200 tests) → 16 files as test/src/client/client_*_test.dart
  • Old shared helpers retired: test/src/fakes.dart and test/src/matchers.dart deleted,
    test/src/mocks.dart shrunk to the seven doubles that live below the harness seam
    (HTTP client, Dio, logger, token/connection-id managers, WS channel/sink, general API).
  • STYLE_GUIDE.md / TESTING.md document the harness and the three conventions it
    depends on (exact-argument stubbing, deterministic fixtures, UTC in emitted events).

The tests now run a real StreamChatClient with three seams replaced — REST API,
WebSocket transport, persistence — so event decoding, channel state, the retry queue,
the delivery reporter and reconnection all execute production code. Several tests
consequently reach a layer deeper than before: they stub api.message.sendMessage
rather than client.sendMessage, putting the client→API translation under test too.

Evidence

master this branch
tests passing 1,693 1,699
lib/ lines covered 6,753 6,817
lines covered on master only 3
verify(...).called(n) 280 299
verifyNoMoreInteractions 124 124 (identical per sub-API target)
any(...) wildcard matchers 753 590
unawaited expectLater 53 3
real network calls escaping the suite 2 0
wall time 1:17 0:42
  • Test-name parity is exact: all 550 test names from the deleted files have a
    counterpart here; verified by runner-level enumeration, not by grep.
  • The 3 remaining uncovered lines are ?? DateTime.now() / ?? Uuid().v4()
    default initializers in poll.dart and message_reminder.dart, no longer reached
    because fixtures pass ids and timestamps explicitly. That is the trade that makes
    equality-based mock matching deterministic.
  • The 2 leaked network calls on master came from a test that built a client without a
    chatApi, sending a real request to chat.stream-io-api.com on every run. The default
    REST wiring those calls incidentally covered is now pinned by
    client_default_wiring_test.dart with a stubbed HttpClientAdapter.

Intentional deviations

  • +6 tests: one pins the channel-with-persistence lifecycle (the old group had
    setUp/tearDown and zero tests); the rest cover channel.config, the auth interceptor's
    non-token-expiry passthrough, the default REST wiring, and the retry queue giving up
    when the policy declines.
  • Four tests titled "non-retriable" actually used retriable errors; they now use
    non-retriable ones, matching their titles.
  • channel.on asserted event identity, which held only because the event never left
    the process. Events now round-trip through real JSON decoding, so it asserts every
    field the event carries instead.
  • client_reconnection_test.dart is a deliberate carve-out on a hand-rolled fake socket:
    the anonymous-token user id cannot pass the fake server's connect-URI validation, and
    the reconnect-recovery tests need to drop an established connection. Both are documented
    in the file, and a self-test in the harness fails the moment the gap closes.

Follow-ups (not in this PR)

  • The harness's guarded zone drops async errors that arrive after the test body completes.
  • ~12s of the suite is wall-clock sleeps straddling production debounce constants; a
    deterministic fix needs a seam to advance them.
  • mockFailedAuth's token-expiry refresh branch is documented but not yet exercised.

Bugs this surfaced (pre-existing on master, filed separately)

  • RetryQueue can re-send the same message an arbitrary number of times: Message.createdAt
    falls back to a fresh DateTime.now() on every read when neither timestamp is set, which
    makes the queue's heap comparator non-reflexive, so remove() silently fails.
  • Expired live locations are never pruned from ChannelClientState.activeLiveLocations for
    messages outside the loaded window — locationExpiredResolver reroutes the event and the
    channel handler no-ops on a _findLocationMessage miss.

Both were invisible on master because its tests mocked StreamChatClient, so no event
resolvers or heap invariants ran.

VelikovPetar and others added 30 commits September 9, 2026 11:43
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…Enabled

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ream_chat_test

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…at_test

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…_test

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…test

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…chat_test

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…_state_test monolith

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…_test

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
VelikovPetar and others added 26 commits September 11, 2026 10:07
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… depending on order

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…tream_chat_test doubles

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…Json restores

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…tialized channels

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…endEvent tests had

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ainst state

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ction_test

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…he error

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ckage widened it

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…el role in emitted messages

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ation claims

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… config

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… whole 0.1.0 surface

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… instead of a default

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…client sendEvent

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… not an isolation boundary

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…API call

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…iry error

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…at other tests

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…sting guides

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@VelikovPetar VelikovPetar changed the title test(llc): migrate the stream_chat test suite to the stream_chat_test harness test(llc): migrate the stream_chat test suite to the stream_chat_test harness Sep 11, 2026
@VelikovPetar VelikovPetar changed the title test(llc): migrate the stream_chat test suite to the stream_chat_test harness test(llc): migrate the stream_chat test suite to the stream_chat_test algebra Sep 11, 2026
@VelikovPetar
VelikovPetar changed the base branch from feat/stream-chat-test-package to master September 11, 2026 18:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant