{"id":50284451,"url":"https://github.com/dappros/ethora-sample-swift","last_synced_at":"2026-05-28T01:30:31.749Z","repository":{"id":357012759,"uuid":"1217011687","full_name":"dappros/ethora-sample-swift","owner":"dappros","description":null,"archived":false,"fork":false,"pushed_at":"2026-05-14T13:32:37.000Z","size":87,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-27T10:32:08.597Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dappros.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-21T13:06:34.000Z","updated_at":"2026-05-14T13:32:41.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/dappros/ethora-sample-swift","commit_stats":null,"previous_names":["dappros/ethora-sample-swift"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/dappros/ethora-sample-swift","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dappros%2Fethora-sample-swift","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dappros%2Fethora-sample-swift/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dappros%2Fethora-sample-swift/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dappros%2Fethora-sample-swift/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dappros","download_url":"https://codeload.github.com/dappros/ethora-sample-swift/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dappros%2Fethora-sample-swift/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33590884,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-27T02:00:06.184Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-05-28T01:30:30.091Z","updated_at":"2026-05-28T01:30:31.743Z","avatar_url":"https://github.com/dappros.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SDK Playground\n\nAn 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`).\n\n\u003e The name **SDKPlayground** is intentionally not `Testing` to avoid confusion with unit / UI tests.\n\n## Build\n\nFrom the `Examples/SDKPlayground` directory:\n\n```bash\n./generate_xcodeproj.sh\nopen SDKPlayground.xcodeproj\n```\n\n**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.\n\nPick the **SDKPlayground** scheme and a simulator. The local package is wired in as `path: ../..` (the `ethora-sdk-swift` repo root).\n\nThe 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.\n\n## Tabs\n\n| Tab | Purpose |\n|-----|---------|\n| **Setup** | API and XMPP settings, auth mode, **Connect** / **Disconnect** |\n| **Chat** | `ChatWrapperView` after a successful Connect |\n| **Logs** | Event stream (incl. `XMPPConnectionStatusChanged`, `XMPPClientDidConnect`, …) |\n\nThe form is persisted to `UserDefaults` (including the password — local-debugging convenience only).\n\n## Regenerating the project\n\nAfter editing `project.yml`:\n\n```bash\n./generate_xcodeproj.sh\n```\n\n## Using SDK Playground Outside This Repository\n\nIf 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.\n\n### What to Copy from the Main Repository\n\nMinimum required:\n- `Package.swift`\n- `Sources/XMPPChatCore`\n- `Sources/XMPPChatUI`\n- `Examples/SDKPlayground` (entire folder)\n\nAlso recommended:\n- `Package.resolved` (to keep dependency versions deterministic)\n\n### Why This Is Required\n\n- `SDKPlayground` imports `XMPPChatCore` and `XMPPChatUI`.\n- These modules are built from the local Swift Package (`Package.swift` + `Sources/...`).\n- `XMPPChatCore` depends on `Starscream`, and that dependency is declared in `Package.swift`.\n\n### Recommended External Workspace Layout\n\n```text\nyour-workspace/\n  Package.swift\n  Sources/\n    XMPPChatCore/\n    XMPPChatUI/\n  Examples/\n    SDKPlayground/\n```\n\n### Run\n\nFrom `Examples/SDKPlayground`:\n\n```bash\n./generate_xcodeproj.sh\nopen SDKPlayground.xcodeproj\n```\n\n### Important Local Package Path Note\n\n`SDKPlayground` is configured to use a local Swift Package at `../..` (from `Examples/SDKPlayground` to the root containing `Package.swift`).  \nIf your external workspace has a different directory depth, update the local package path in Xcode (or in `project.yml`).\n\n## Testing\n\nThis repo hosts the **Layer 2** end-to-end test flows for the Ethora\niOS SDK. Layer 1 (hermetic XCTest unit tests) lives in\n[`ethora-sdk-swift`](https://github.com/dappros/ethora-sdk-swift#testing)\nalongside the source it exercises.\n\n### What runs here\n\n[`.maestro/`](.maestro/) holds 19 [Maestro](https://maestro.mobile.dev/)\nYAML flows that drive the SDKPlayground app on an iOS Simulator\nagainst `chat-qa.ethora.com`. The same 19 flow YAMLs (with the\nsame numbering and intent) drive the Android sample app on Android\nemulators — see\n[`ethora-sample-android/.maestro/`](https://github.com/dappros/ethora-sample-android/tree/main/.maestro).\n\nThey run on the sample's CI ([`.github/workflows/maestro.yml`](.github/workflows/maestro.yml))\non every push, PR, and SDK release tag — the gate that catches\nintegration regressions like config drift, preset URL breakage, or\ncross-platform feature parity gaps.\n\n| # | Flow | Covers |\n|---|------|--------|\n| 01 | login-email | Happy-path email/password login → connected |\n| 02 | login-jwt | Bring-your-own-auth client-flow JWT |\n| 03 | list-rooms | Room list renders post-login with unread counts |\n| 04 | send-text | XMPP send round-trip |\n| 05 | receive-text | MAM delivery from a second user |\n| 06 | attach-file | Upload + image bubble |\n| 07 | reconnect-airplane | Disconnect → reconnect → history survives |\n| 08 | push-deep-link | APNs payload → correct room |\n| 09 | logout-relogin | State isolation across sessions |\n| 10 | switch-app | Multi-tenant app switcher |\n| 11 | login-wrong-password | Negative path surfaces error to UI |\n| 13 | message-edit | Long-press → Edit → bubble updates |\n| 14 | message-delete | Long-press → Delete → tombstone or removal |\n| 15 | message-reaction | Long-press → React → emoji + count visible |\n| 16 | create-room | \"+\" → name → room visible + writable |\n| 17 | search-rooms | `.searchable` filter narrows + restores list |\n| 18 | multi-message-rapid | 5 rapid sends, ordering preserved |\n| 19 | room-info | Room info modal → participants + leave control |\n| 20 | offline-pending-resend | Send while disconnected → message lands after reconnect |\n\n(Flow 12 reserved for typing-indicator — needs a `sendAsBob`-style\nhelper for XMPP composing-state.)\n\nFull coverage table with per-flow assertions and the regression\nclasses each catches:\n[`.maestro/README.md`](.maestro/README.md#coverage-table).\n\n### Adding a new flow\n\nEach flow is ~10–30 lines of YAML; copy\n[`flows/01-login-email.yaml`](.maestro/flows/01-login-email.yaml)\nas a template. See [`.maestro/README.md`](.maestro/README.md) for\nauthoring conventions and how to run flows locally.\n\n### Cross-platform testing overview\n\nThis iOS sample's Maestro flows are part of a four-platform testing\nstack. The same flow YAMLs run against Android via\n[`ethora-sample-android/.maestro/`](https://github.com/dappros/ethora-sample-android/tree/main/.maestro)\n— selectors resolve by accessibility-id strings that match across\niOS `accessibilityIdentifier`, Android `testTag`, and Web `data-testid`.\n\n| Layer 1 (hermetic) | Layer 2 (E2E) |\n|--------------------|----------------|\n| [`ethora-sdk-swift`](https://github.com/dappros/ethora-sdk-swift) — XCTest + `accessibilityIdentifier` markers | `ethora-sample-swift/.maestro/` — 19 flows (this repo) |\n| [`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 |\n| [`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 |\n\nA Maestro `id: \"chat_input\"` resolves the same intent on iOS and\nAndroid. Selectors are 4-repo-coupled — keep them in sync.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdappros%2Fethora-sample-swift","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdappros%2Fethora-sample-swift","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdappros%2Fethora-sample-swift/lists"}