Skip to content

test: add Detox e2e suite with a dedicated E2ETestApp - #3881

Open
testableapple wants to merge 15 commits into
developfrom
alexeyalterpesotskiy/rn-449-e2e-infra
Open

testableapple wants to merge 15 commits into
developfrom
alexeyalterpesotskiy/rn-449-e2e-infra

Conversation

@testableapple

@testableapple testableapple commented Oct 20, 2026 •

Copy link
Copy Markdown
Member

🎯 Goal

E2E test automation for the SDK, on par with the native iOS/Android and Flutter suites, running on PRs.

Linear: RN-450, RN-451, RN-452, RN-453, RN-454, RN-455, RN-457 (parent RN-449)

🛠 Implementation details

Dedicated app: examples/E2ETestApp. A new bare RN 0.88 workspace with only the SDK and its required peer dependencies (no Firebase, maps, video or navigation library), like the native SDKs' StreamChatUITestsApp. It has three screens: a user selector, the channel list, and a channel stacked over the list. It reads a MOCK_SERVER_URL launch argument (react-native-launch-arguments), never persists a login and runs without offline storage, so every test starts clean. A clean Release build takes ~2 min on an M-series Mac; the SampleApp took ~15 min on Android. The SampleApp app is unchanged; only its Fastfile gains the e2e lanes.

Framework (RN-450): Detox 20 + Jest 30 in examples/E2ETestApp/e2e/, with ios.sim.*, android.emu.* and android.att.* configs (debug and release).

Mock server (RN-451): the shared stream-chat-test-mock-server, one server per test through its driver (port 4569).

Page objects (RN-452) and robots (RN-453, RN-454, RN-455): structure and naming follow the native suites:

  • BackendRobot / ParticipantRobot: 1:1 ports of the Android robots
  • UserRobot + UserRobot*Asserts: assert extensions, like Android's
  • LoginPage / ChannelListPage / MessageListPage
  • setUpStreamTestCase(), step(), and uiautomator-style element helpers

Robots chain fluently like the native ones: await userRobot.login().openChannel().assertMessage('Hi').

Smoke suite: 6 tests (MessageList ×3, ChannelList ×3), named after their Android counterparts and keeping the native expectations.

SDK (additive testIDs only): channel-preview-title, channel-preview-message, channel-preview-sender, and message-status-{read,delivered,sending,sent}, with a unit test.

CI (RN-457): .github/workflows/e2e-test.yml.

  • Android runs on PRs: ubuntu-latest, KVM, API 36 AOSP emulator, pixel profile (the native Android SDK's setup).
  • iOS runs only on demand (workflow_dispatch with ios: true), not on PRs, to save CI time and macOS runners: macos-15, Xcode 26.2, iPhone 17 Pro.
  • Gated like the iOS SDK: a cheap Check E2E Required job runs is_check_required over the e2e sources (Fastfile impact_analysis), and test_e2e checks it too.
  • Test E2E Result is the check to require in branch protection. It covers Android (it doesn't wait for iOS) and passes when the Android job passes or is skipped as not required.
  • Caching:
    • the built .app / .apk, keyed on the app and SDK sources but not on e2e/, so a test-only change skips the native build
    • node_modules of yarn workspaces focus e2etestapp
    • CocoaPods, ccache (with CCACHE_BINARY exported, without which RN's ccache wrappers silently skip ccache), the Detox framework, Gradle (cache-read-only: false, since setup-gradle otherwise only writes on the default branch), and the mock server's gems
    • each PR fills its own caches (the workflow doesn't run on develop): its first run builds cold, and later pushes reuse them
  • On failure, uploads the mock server logs, Detox's logs and screenshots, and the emulator's crash data.

Fastlane (in examples/SampleApp/fastlane, next to the repo's other lanes): start_mock_server, stop_mock_server, e2e_pod_install, test_e2e, e2e_check_required.

Notable findings, documented in examples/E2ETestApp/e2e/README.md:

  • Fabric mounts some testID'd views (message-list-item-*, message-text-container) empty, with their content as siblings, so page objects scope to message-content-wrapper or the list instead.
  • iOS runs without Detox's idle synchronization, which can wedge on RN's UIManager shadow queue. Robots wait explicitly, and taps retry while the target isn't hittable yet.
  • launchApp({ permissions }) makes Detox restart SpringBoard once per permission on every launch. On CI that cost 1.5–3 min per test, so the suite doesn't pass any.
  • Android sets the composer text directly (as the native suite does). Typing through Gboard left the text in a composing state that the composer didn't send.

How to run and extend the suite: examples/E2ETestApp/e2e/README.md.

🎨 UI Changes

None (testIDs only).

🧪 Testing

Not covered yet: Allure TestOps reporting, full suite ports, and iOS on PRs (manual runs only, to save CI time and macOS runners).

☑️ Checklist

  • I have signed the Stream CLA (required)
  • PR targets the develop branch
  • Documentation is updated
  • New code is tested in main example apps, including all possible scenarios
    • SampleApp iOS and Android
    • Expo iOS and Android

@testableapple
testableapple marked this pull request as ready for review October 20, 2026 18:09
@testableapple testableapple changed the title feat(SampleApp): add Detox e2e suite with mock server, robots and page objects test: add Detox e2e suite with a dedicated E2ETestApp Oct 20, 2026
@Stream-SDK-Bot

Copy link
Copy Markdown
Contributor

SDK Size

title develop branch diff status
js_bundle_size 2036 KB 2036 KB +252 B 🟢
ai_components_size 130 KB 130 KB 0 B 🟢

This branch has not been deployed

No deployments
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.

2 participants