https://github.com/dappros/ethora-sample-swift
https://github.com/dappros/ethora-sample-swift
Last synced: 15 days ago
JSON representation
- Host: GitHub
- URL: https://github.com/dappros/ethora-sample-swift
- Owner: dappros
- Created: 2026-04-21T13:06:34.000Z (about 2 months ago)
- Default Branch: main
- Last Pushed: 2026-05-14T13:32:37.000Z (29 days ago)
- Last Synced: 2026-05-27T10:32:08.597Z (16 days ago)
- Language: Swift
- Size: 85 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# SDK Playground
An interactive iOS app **inside the SDK repository** for quickly exercising `XMPPChatCore` + `XMPPChatUI`: enter the environment (Base URL, app token, XMPP), sign in via **JWT** (`/users/client`) or **email/password** (`/users/login-with-email`), then use the chat and the **Logs** tab (XMPP events from `NotificationCenter`).
> The name **SDKPlayground** is intentionally not `Testing` to avoid confusion with unit / UI tests.
## Build
From the `Examples/SDKPlayground` directory:
```bash
./generate_xcodeproj.sh
open SDKPlayground.xcodeproj
```
**Important:** do not run `xcodegen generate` on its own — XcodeGen doesn't wire the local SPM `package` link, and Xcode then reports *Missing package product 'XMPPChatCore' / 'XMPPChatUI'*. The `generate_xcodeproj.sh` script runs `xcodegen` and then `fix_local_package_refs.py` to patch that reference.
Pick the **SDKPlayground** scheme and a simulator. The local package is wired in as `path: ../..` (the `ethora-sdk-swift` repo root).
The project **must** be opened from `ethora-sdk-swift/Examples/SDKPlayground/`. If you copy only the `SDKPlayground` folder into a different repository without the package root, the relative `../..` path to `Package.swift` breaks — fix the local-package path in Xcode in that case.
## Tabs
| Tab | Purpose |
|-----|---------|
| **Setup** | API and XMPP settings, auth mode, **Connect** / **Disconnect** |
| **Chat** | `ChatWrapperView` after a successful Connect |
| **Logs** | Event stream (incl. `XMPPConnectionStatusChanged`, `XMPPClientDidConnect`, …) |
The form is persisted to `UserDefaults` (including the password — local-debugging convenience only).
## Regenerating the project
After editing `project.yml`:
```bash
./generate_xcodeproj.sh
```
## Using SDK Playground Outside This Repository
If you run `SDKPlayground` in another repository/workspace, you need to move not only the playground project itself, but also the SDK sources it depends on.
### What to Copy from the Main Repository
Minimum required:
- `Package.swift`
- `Sources/XMPPChatCore`
- `Sources/XMPPChatUI`
- `Examples/SDKPlayground` (entire folder)
Also recommended:
- `Package.resolved` (to keep dependency versions deterministic)
### Why This Is Required
- `SDKPlayground` imports `XMPPChatCore` and `XMPPChatUI`.
- These modules are built from the local Swift Package (`Package.swift` + `Sources/...`).
- `XMPPChatCore` depends on `Starscream`, and that dependency is declared in `Package.swift`.
### Recommended External Workspace Layout
```text
your-workspace/
Package.swift
Sources/
XMPPChatCore/
XMPPChatUI/
Examples/
SDKPlayground/
```
### Run
From `Examples/SDKPlayground`:
```bash
./generate_xcodeproj.sh
open SDKPlayground.xcodeproj
```
### Important Local Package Path Note
`SDKPlayground` is configured to use a local Swift Package at `../..` (from `Examples/SDKPlayground` to the root containing `Package.swift`).
If your external workspace has a different directory depth, update the local package path in Xcode (or in `project.yml`).
## Testing
This repo hosts the **Layer 2** end-to-end test flows for the Ethora
iOS SDK. Layer 1 (hermetic XCTest unit tests) lives in
[`ethora-sdk-swift`](https://github.com/dappros/ethora-sdk-swift#testing)
alongside the source it exercises.
### What runs here
[`.maestro/`](.maestro/) holds 19 [Maestro](https://maestro.mobile.dev/)
YAML flows that drive the SDKPlayground app on an iOS Simulator
against `chat-qa.ethora.com`. The same 19 flow YAMLs (with the
same numbering and intent) drive the Android sample app on Android
emulators — see
[`ethora-sample-android/.maestro/`](https://github.com/dappros/ethora-sample-android/tree/main/.maestro).
They run on the sample's CI ([`.github/workflows/maestro.yml`](.github/workflows/maestro.yml))
on every push, PR, and SDK release tag — the gate that catches
integration regressions like config drift, preset URL breakage, or
cross-platform feature parity gaps.
| # | Flow | Covers |
|---|------|--------|
| 01 | login-email | Happy-path email/password login → connected |
| 02 | login-jwt | Bring-your-own-auth client-flow JWT |
| 03 | list-rooms | Room list renders post-login with unread counts |
| 04 | send-text | XMPP send round-trip |
| 05 | receive-text | MAM delivery from a second user |
| 06 | attach-file | Upload + image bubble |
| 07 | reconnect-airplane | Disconnect → reconnect → history survives |
| 08 | push-deep-link | APNs payload → correct room |
| 09 | logout-relogin | State isolation across sessions |
| 10 | switch-app | Multi-tenant app switcher |
| 11 | login-wrong-password | Negative path surfaces error to UI |
| 13 | message-edit | Long-press → Edit → bubble updates |
| 14 | message-delete | Long-press → Delete → tombstone or removal |
| 15 | message-reaction | Long-press → React → emoji + count visible |
| 16 | create-room | "+" → name → room visible + writable |
| 17 | search-rooms | `.searchable` filter narrows + restores list |
| 18 | multi-message-rapid | 5 rapid sends, ordering preserved |
| 19 | room-info | Room info modal → participants + leave control |
| 20 | offline-pending-resend | Send while disconnected → message lands after reconnect |
(Flow 12 reserved for typing-indicator — needs a `sendAsBob`-style
helper for XMPP composing-state.)
Full coverage table with per-flow assertions and the regression
classes each catches:
[`.maestro/README.md`](.maestro/README.md#coverage-table).
### Adding a new flow
Each flow is ~10–30 lines of YAML; copy
[`flows/01-login-email.yaml`](.maestro/flows/01-login-email.yaml)
as a template. See [`.maestro/README.md`](.maestro/README.md) for
authoring conventions and how to run flows locally.
### Cross-platform testing overview
This iOS sample's Maestro flows are part of a four-platform testing
stack. The same flow YAMLs run against Android via
[`ethora-sample-android/.maestro/`](https://github.com/dappros/ethora-sample-android/tree/main/.maestro)
— selectors resolve by accessibility-id strings that match across
iOS `accessibilityIdentifier`, Android `testTag`, and Web `data-testid`.
| Layer 1 (hermetic) | Layer 2 (E2E) |
|--------------------|----------------|
| [`ethora-sdk-swift`](https://github.com/dappros/ethora-sdk-swift) — XCTest + `accessibilityIdentifier` markers | `ethora-sample-swift/.maestro/` — 19 flows (this repo) |
| [`ethora-sdk-android`](https://github.com/dappros/ethora-sdk-android) — Compose UI tests | [`ethora-sample-android/.maestro/`](https://github.com/dappros/ethora-sample-android) — same 19 flows on Android emulator |
| [`ethora-chat-component`](https://github.com/dappros/ethora-chat-component) — Vitest + RTL + `data-testid` | [`ethora-app-reactjs/tests/e2e/`](https://github.com/dappros/ethora-app-reactjs) — Playwright |
A Maestro `id: "chat_input"` resolves the same intent on iOS and
Android. Selectors are 4-repo-coupled — keep them in sync.