Skip to content

Commit ad4ecdb

Browse files
committed
fix(test): correct iOS platform version format
1 parent db89571 commit ad4ecdb

2 files changed

Lines changed: 119 additions & 57 deletions

File tree

appium/wdio.ios.conf.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const config: WebdriverIO.Config = {
99
platformName: 'iOS',
1010
'appium:app': isLocal ? process.env.APP_PATH : process.env.BROWSERSTACK_APP_URL,
1111
'appium:deviceName': process.env.DEVICE || 'iPhone 17',
12-
'appium:platformVersion': process.env.OS_VERSION || '26 latest',
12+
'appium:platformVersion': process.env.OS_VERSION || '26',
1313
'appium:automationName': 'XCUITest',
1414
...(process.env.BUNDLE_ID ? { 'appium:bundleId': process.env.BUNDLE_ID } : {}),
1515
'appium:autoAcceptAlerts': false,

demo/build.md

Lines changed: 118 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ Plain class (not tied to UI framework) injected into the state management layer.
5050
- **Push subscription**: getPushSubscriptionId() -> nullable, isPushOptedIn() -> nullable bool, optInPush(), optOutPush()
5151
- **Notifications**: hasPermission() -> bool, requestPermission(fallbackToSettings) -> async bool, clearAll()
5252
- **In-App Messages**: setPaused(bool)
53-
- **Location**: setLocationShared(bool), requestLocationPermission()
53+
- **Location**: setLocationShared(bool), isLocationShared() -> async bool, requestLocationPermission()
5454
- **Privacy consent**: setConsentRequired(bool), setConsentGiven(bool)
5555
- **User IDs**: getExternalId() -> nullable, getOnesignalId() -> nullable
5656
- **Live Activities** (iOS only): startDefaultLiveActivity(activityId, attributes, content)
@@ -137,17 +137,17 @@ Clean up listeners on teardown (if platform requires it).
137137
7. **Aliases Section** (Add/Add Multiple, read-only list)
138138
8. **Emails Section** (Collapsible list >5)
139139
9. **SMS Section** (Collapsible list >5)
140-
10. **Tags Section** (Add/Add Multiple/Remove Selected)
141-
11. **Outcome Events Section** (Send Outcome with type selection)
142-
12. **Triggers Section** (Add/Add Multiple/Remove Selected/Clear All - IN MEMORY ONLY)
143-
13. **Track Event Section** (JSON validation)
144-
14. **Location Section** (Shared toggle, Prompt button)
140+
10. **Tags Section** (Add Tag/Add Multiple Tags/Remove Tags)
141+
11. **Outcomes Section** (Send Outcome with type selection)
142+
12. **Triggers Section** (Add Trigger/Add Multiple Triggers/Remove Triggers/Clear All Triggers - IN MEMORY ONLY)
143+
13. **Custom Events Section** (JSON validation)
144+
14. **Location Section** (Shared toggle, Prompt button, Check button)
145145
15. **Live Activities Section** (iOS only - Start, Update, End)
146-
16. **Next Page Button**
146+
16. **Next Screen Button**
147147

148148
### Prompt 2.1a - App Section
149149

150-
1. App ID display (readonly text)
150+
1. App ID display (readonly text). When `E2E_MODE=true`, mask the value with bullet characters for deterministic screenshots.
151151
2. Sticky guidance banner:
152152
- "Add your own App ID, then rebuild to fully test all functionality."
153153
- Link: "Get your keys at onesignal.com" (opens browser)
@@ -173,7 +173,7 @@ Separate SectionCard titled "User":
173173
### Prompt 2.2 - Push Section
174174

175175
- Title: "Push" with info icon
176-
- Push Subscription ID (readonly)
176+
- Push Subscription ID (readonly). When `E2E_MODE=true`, mask the value with bullet characters.
177177
- Enabled toggle (optIn/optOut), disabled when permission NOT granted
178178
- Auto-request permission when home screen loads
179179
- PROMPT PUSH button: only visible when permission NOT granted, hidden once granted
@@ -212,9 +212,9 @@ Separate SectionCard titled "User":
212212
- Title: "Aliases" with info icon
213213
- Stacked key-value list (read-only, no delete icons, see styles.md "Stacked" layout)
214214
- Filter out "external_id" and "onesignal_id" from display
215-
- "No Aliases Added" when empty
216-
- ADD -> PairInputDialog (Label + ID on same row)
217-
- ADD MULTIPLE -> MultiPairInputDialog
215+
- "No aliases added" when empty
216+
- ADD ALIAS -> PairInputDialog (Label + ID on same row)
217+
- ADD MULTIPLE ALIASES -> MultiPairInputDialog
218218
- No remove functionality (aliases are add-only)
219219

220220
### Prompt 2.7 - Emails Section
@@ -236,14 +236,14 @@ Separate SectionCard titled "User":
236236

237237
- Title: "Tags" with info icon
238238
- Stacked key-value list with X icon (remove action)
239-
- "No Tags Added" when empty
240-
- ADD -> PairInputDialog (Key + Value)
241-
- ADD MULTIPLE -> MultiPairInputDialog
242-
- REMOVE SELECTED (only when tags exist) -> MultiSelectRemoveDialog
239+
- "No tags added" when empty
240+
- ADD TAG -> PairInputDialog (Key + Value)
241+
- ADD MULTIPLE TAGS -> MultiPairInputDialog
242+
- REMOVE TAGS (only when tags exist) -> MultiSelectRemoveDialog
243243

244-
### Prompt 2.10 - Outcome Events Section
244+
### Prompt 2.10 - Outcomes Section
245245

246-
- Title: "Outcome Events" with info icon
246+
- Title: "Outcomes" with info icon
247247
- SEND OUTCOME -> dialog with 3 radio options:
248248
1. Normal Outcome -> name field
249249
2. Unique Outcome -> name field
@@ -252,16 +252,16 @@ Separate SectionCard titled "User":
252252
### Prompt 2.11 - Triggers Section (IN MEMORY ONLY)
253253

254254
- Title: "Triggers" with info icon
255-
- Same list/button pattern as Tags, plus:
256-
- CLEAR ALL button (only when triggers exist)
255+
- Same list/button pattern as Tags (ADD TRIGGER, ADD MULTIPLE TRIGGERS, REMOVE TRIGGERS), plus:
256+
- CLEAR ALL TRIGGERS button (only when triggers exist)
257257
- Triggers are IN MEMORY ONLY: not persisted, cleared on restart
258258
- Sending an IAM also upserts `iam_type` in this list
259259
- Transient test data for IAM testing
260260

261-
### Prompt 2.12 - Track Event Section
261+
### Prompt 2.12 - Custom Events Section
262262

263-
- Title: "Track Event" with info icon
264-
- TRACK EVENT -> TrackEventDialog:
263+
- Title: "Custom Events" with info icon
264+
- TRACK EVENT -> TrackEventDialog (dialog title: "Custom Event"):
265265
- "Event Name" (required, error if empty)
266266
- "Properties (optional, JSON)" with placeholder `{"key": "value"}`
267267
- Invalid JSON shows "Invalid JSON format" error
@@ -274,6 +274,7 @@ Separate SectionCard titled "User":
274274
- Title: "Location" with info icon
275275
- Toggle: "Location Shared" / "Share device location with OneSignal"
276276
- PROMPT LOCATION button
277+
- CHECK LOCATION SHARED button -> queries SDK and shows snackbar "Location shared: {bool}"
277278

278279
### Prompt 2.14 - Live Activities Section (iOS Only)
279280

@@ -304,16 +305,19 @@ Widget extension requirements:
304305
- Status-based theming: preparing (orange), on_the_way (blue), delivered (green)
305306
- If the file `examples/demo/ios/OneSignalWidget/OneSignalWidgetLiveActivity.swift` already exists, replace its contents with the shared reference implementation at `https://raw.githubusercontent.com/OneSignal/sdk-shared/main/demo/LiveActivity.swift`
306307

307-
API key setup:
308+
Environment / API key setup:
308309

309-
- Store REST API key in `.env` file (e.g. `ONESIGNAL_API_KEY=your_rest_api_key`)
310-
- Provide `.env.example` with placeholder value
310+
- `.env` file with two variables:
311+
- `ONESIGNAL_APP_ID=your-onesignal-app-id` (overrides default app ID; falls back to default if empty or missing)
312+
- `ONESIGNAL_API_KEY=your-onesignal-api-key` (required for Live Activity update/end)
313+
- `E2E_MODE=true` (optional, masks sensitive IDs in the UI for deterministic Appium screenshots)
314+
- Provide `.env.example` with placeholder values and a comment noting the default app ID
311315
- Add `.env` to `.gitignore`
312316
- `hasApiKey()` on the API service checks that the key is present and not the placeholder
313317

314318
### Prompt 2.15 - Secondary Screen
315319

316-
Launched by "Next Screen" button at bottom of main screen:
320+
Launched by "NEXT SCREEN" button at bottom of main screen:
317321

318322
- Title: "Secondary Screen"
319323
- Centered large headline text "Secondary Screen"
@@ -373,7 +377,7 @@ SectionCard has optional info icon -> onInfoTap callback -> shows TooltipDialog
373377

374378
### Persisted (local storage)
375379

376-
PreferencesService: App ID, consent required, privacy consent, external user ID, location shared, IAM paused.
380+
PreferencesService: consent required, privacy consent, external user ID, location shared, IAM paused. App ID is read from `.env` (not persisted in preferences).
377381

378382
### Initialization Flow
379383

@@ -412,6 +416,75 @@ All dialog fields EMPTY by default. Appium enters:
412416

413417
Add Multiple dialogs use the same values for the first row and support multiple rows.
414418

419+
### Prompt 6.2 - Accessibility Identifiers (Appium)
420+
421+
Use the platform's accessibility/test ID mechanism (e.g. `Semantics(identifier:)` in Flutter, `accessibilityIdentifier` in iOS, `testID` in React Native). These identifiers allow Appium to locate elements reliably.
422+
423+
**Scroll view**: `main_scroll_view`
424+
425+
**Section containers**: Each section has `{sectionKey}_section` wrapping it. Info icons have `{sectionKey}_info_icon`.
426+
427+
Section keys: `app`, `user`, `push`, `send_push`, `iam`, `send_iam`, `aliases`, `emails`, `sms`, `tags`, `outcomes`, `triggers`, `custom_events`, `location`, `live_activities`
428+
429+
**Value displays**:
430+
431+
| Identifier | Element |
432+
| ---------------------- | --------------------------------- |
433+
| `app_id_value` | App ID text |
434+
| `push_id_value` | Push Subscription ID text |
435+
| `user_status_value` | User status (Anonymous/Logged In) |
436+
| `user_external_id_value` | External ID text |
437+
438+
**Buttons**:
439+
440+
| Identifier | Button |
441+
| ------------------------ | --------------------------------------- |
442+
| `login_user_button` | Login / Switch User |
443+
| `logout_user_button` | Logout User |
444+
| `send_simple_button` | Simple notification |
445+
| `send_image_button` | Image notification |
446+
| `send_sound_button` | Sound notification |
447+
| `send_custom_button` | Custom notification |
448+
| `clear_all_button` | Clear all notifications |
449+
| `add_tag_button` | Add Tag |
450+
451+
**Toggles**:
452+
453+
| Identifier | Toggle |
454+
| ------------------------ | --------------------------------------- |
455+
| `push_enabled_toggle` | Push Enabled |
456+
| `pause_iam_toggle` | Pause In-App Messages |
457+
458+
**Dialog inputs** (passed as parameters to reusable dialog components):
459+
460+
| Identifier | Dialog field |
461+
| ------------------------- | -------------------------------------- |
462+
| `login_user_id_input` | Login External User Id |
463+
| `login_confirm_button` | Login confirm |
464+
| `alias_label_input` | Add Alias label field |
465+
| `alias_id_input` | Add Alias ID field |
466+
| `alias_confirm_button` | Add Alias confirm |
467+
| `tag_key_input` | Add Tag key field |
468+
| `tag_value_input` | Add Tag value field |
469+
| `tag_confirm_button` | Add Tag confirm |
470+
| `trigger_key_input` | Add Trigger key field |
471+
| `trigger_value_input` | Add Trigger value field |
472+
| `trigger_confirm_button` | Add Trigger confirm |
473+
| `outcome_name_input` | Outcome name field |
474+
| `outcome_value_input` | Outcome value field |
475+
| `outcome_send_button` | Outcome send button |
476+
| `event_name_input` | Custom Event name field |
477+
| `event_properties_input` | Custom Event properties field |
478+
| `event_track_button` | Custom Event track button |
479+
| `tooltip_title` | Tooltip dialog title |
480+
| `tooltip_description` | Tooltip dialog description |
481+
482+
**List items**: Generated from `sectionKey` parameter:
483+
- Key-value pairs: `{sectionKey}_pair_key_{keyText}`, `{sectionKey}_pair_value_{keyText}`
484+
- Remove buttons: `{sectionKey}_remove_{keyText}` or `{sectionKey}_remove_{text}`
485+
- Multi-select checkboxes: `remove_checkbox_{key}`
486+
- Multi-pair rows: `{keyLabel}_input_{index}`, `{valueLabel}_input_{index}`
487+
415488
---
416489

417490
## Phase 7: Implementation Details
@@ -434,12 +507,12 @@ Single state container at app root. Holds all UI state with public getters. Expo
434507

435508
### Prompt 8.2 - Reusable Components
436509

437-
- **SectionCard**: card with title, optional info icon, content slot, onInfoTap callback
438-
- **ToggleRow**: label, optional description, toggle control
439-
- **ActionButton**: PrimaryButton (filled) and OutlinedButton (for secondary/destructive actions), full-width, per styles.md
440-
- **ListWidgets**: PairItem (key-value + optional delete), SingleItem (value + delete), EmptyState, CollapsibleList (5 items then expandable), PairList
510+
- **SectionCard**: card with title, optional info icon, content slot, onInfoTap callback, optional `sectionKey` for accessibility identifiers (generates `{sectionKey}_section` on the container and `{sectionKey}_info_icon` on the info button)
511+
- **ToggleRow**: label, optional description, toggle control, optional `semanticsLabel` for accessibility identifier
512+
- **ActionButton**: PrimaryButton (filled) and DestructiveButton (outlined, for secondary/destructive actions), full-width, per styles.md. Both accept optional `semanticsLabel` for accessibility identifier.
513+
- **ListWidgets**: PairItem (key-value + optional delete), SingleItem (value + delete), EmptyState, CollapsibleList (5 items then expandable), PairList. All list widgets accept a required `sectionKey` for generating accessibility identifiers (e.g. `{sectionKey}_pair_key_{keyText}`, `{sectionKey}_remove_{keyText}`).
441514
- **LoadingOverlay**: full-screen spinner overlay per styles.md
442-
- **Dialogs**: all full-width with consistent padding
515+
- **Dialogs**: all full-width with consistent padding. Dialogs accept optional semantics label parameters for key inputs and confirm buttons (e.g. `keySemanticsLabel`, `valueSemanticsLabel`, `confirmSemanticsLabel`).
443516
- SingleInputDialog, PairInputDialog (same row), MultiPairInputDialog (dynamic rows, dividers, X to delete, batch submit), MultiSelectRemoveDialog (checkboxes, batch remove)
444517
- LoginDialog, OutcomeDialog, TrackEventDialog, CustomNotificationDialog, TooltipDialog
445518

@@ -455,7 +528,7 @@ Shared by Aliases, Tags, and Triggers ADD MULTIPLE buttons.
455528

456529
### Prompt 8.4 - MultiSelectRemoveDialog
457530

458-
Shared by Tags and Triggers REMOVE SELECTED buttons.
531+
Shared by Tags and Triggers REMOVE buttons.
459532

460533
- Checkbox per item, label shows key only
461534
- "Remove (N)" button shows selected count, disabled when none
@@ -467,37 +540,26 @@ All styling defined in: `https://raw.githubusercontent.com/OneSignal/sdk-shared/
467540

468541
Implement theme constants/tokens mapping style reference to the platform's theming system.
469542

470-
### Prompt 8.6 - Log View (Appium-Ready)
471-
472-
Collapsible log view at top of screen.
473-
474-
LogManager: singleton with reactive updates, API: d(tag, message), i(), w(), e(), also prints to console.
475-
476-
LogView: layout per styles.md Logs View section, 100dp list height, newest first, trash icon when entries exist.
543+
### Prompt 8.6 - Feedback Messages (SnackBar/Toast)
477544

478-
Appium IDs: `log_view_container`, `log_view_header`, `log_view_count`, `log_view_clear_button`, `log_view_list`, `log_view_empty`, `log_entry_{N}`, `log_entry_{N}_timestamp`, `log_entry_{N}_level`, `log_entry_{N}_message`
545+
Feedback messages are shown directly from the UI layer (not centralized in the state management layer). Use a `BuildContext` extension or helper that calls the platform's transient message API (SnackBar/Toast). The extension should hide the current message before showing a new one. Show snackbars from UI widget callbacks after awaiting the action, using a context-mounted check before displaying.
479546

480-
Use the platform's accessibility/test ID mechanism.
547+
Only the following actions show snackbar feedback from the UI:
481548

482-
### Prompt 8.7 - Feedback Messages
549+
- Login/Logout: "Logged in as {userId}" / "User logged out"
550+
- Outcomes: "Outcome sent: {name}" / "Unique outcome sent: {name}" / "Outcome sent: {name} = {value}"
551+
- Custom Events: "Event tracked: {name}"
552+
- Location check: "Location shared: {bool}"
483553

484-
All actions show brief feedback via platform's transient message (SnackBar/Toast):
485-
486-
- Login/Logout: "Logged in as: {userId}" / "Logged out"
487-
- Add/remove items: "Alias added: {label}", "{count} alias(es) added", etc.
488-
- Notifications: "Notification sent: {type}" / "Failed to send notification"
489-
- IAM: "Sent In-App Message: {type}"
490-
- Outcomes: "Outcome sent: {name}"
491-
- Events: "Event tracked: {name}"
492-
- Live Activities: "Started Live Activity: {activityId}", "Updated Live Activity: {activityId}", "Ended Live Activity: {activityId}" / "Failed to update Live Activity" / "Failed to end Live Activity"
493-
494-
Clear previous message before showing new. All messages also logged via LogManager.i().
554+
All other actions (add/remove items, notifications, IAM, live activities, etc.) use `debugPrint()` / console logging only -- no snackbar. The state management layer should NOT hold snackbar state or expose snackbar messages. Use `debugPrint()` for all internal logging instead of a custom LogManager.
495555

496556
---
497557

498558
## Configuration
499559

500-
Default app id: `77e32082-ea27-42e3-a898-c72e141824ef`
560+
Default app id: `77e32082-ea27-42e3-a898-c72e141824ef` (used when `ONESIGNAL_APP_ID` env var is empty or missing)
561+
562+
App ID is loaded from the `.env` file's `ONESIGNAL_APP_ID` variable at startup, NOT from local preferences. If the env var is empty or absent, fall back to the default app ID above.
501563

502564
REST API key is NOT required for the fetchUser endpoint.
503565

0 commit comments

Comments
 (0)