19 KiB
Lotus Chat — Manual Testing Guide
Generated: June 2026
Scope: Everything landed on the lotus branch since the v4.12.3 merge that I (Claude) could not verify statically and that needs a human in a real environment to confirm. Work through it top-to-bottom; the highest-risk / hardest-to-reproduce items are first.
How to report back: For each numbered check, tell me PASS / FAIL (or partial). On any FAIL, include: what you saw vs. expected, the browser/OS (and whether web LXC 106 or the desktop/Tauri build), the theme you were on, and any browser console errors (F12 → Console). Screenshots help for anything visual.
Environment notes
- You push from your own machine; these commits are local on
lotusuntil you do. - Test the web build (LXC 106 /
code.lotusguild.org) first; re-run the call + poll sections on the desktop (Tauri) build too, since CSP and the EC iframe behave differently there. - Several call features need a second participant (second account on another device/browser, or a colleague). Items that need this are marked 👥 2 people.
- A couple of call items need a third room/call in parallel — marked 👥👥.
Commits covered
| Commit | Area |
|---|---|
caf6318a |
Poll vote buttons → folds tokens (N4) |
c67aed01 |
In-call incoming-call banner (#4b) |
4a875884 |
Selectable ringtone (#4a) |
0394fce9 |
EC iframe load watchdog + recovery UI; avatar decorations on call tiles (#3) |
d2946c00 |
Upload retry/backoff, presence-on-unload, typed m.direct |
b7e1f89c |
Timeline/composer/emoji perf memoization |
c0f98672 |
Upstream Element Call 0.20.1 merge (regression sweep) |
A. Calls — new ringtone + notification work (highest priority)
A1. Ringtone selection — preview in Settings
Steps
- Open Settings → General, scroll to the Calls section.
- Find the new Ringtone dropdown (just above Ringtone Volume).
- Select each option in turn: Classic, Chime, Soft, Retro, Silent.
Expected
- Selecting Classic plays the existing
call.oggclip (cut off after a few seconds). - Chime / Soft / Retro each play a short, distinct synthesized preview.
- Silent plays nothing.
- Changing Ringtone Volume then re-selecting a ringtone previews at the new volume.
- No console errors.
⚠️ Known browser limitation: the synthesized tones use WebAudio. If a preview is ever silent, click anywhere on the page once (a "user gesture") and retry — browsers suspend audio until the page has been interacted with. The Settings preview is after a click so it should always sound; this note matters more for A3.
A2. Ringtone selection persists
- Set Ringtone to Retro, reload the app.
- Expected: the dropdown still shows Retro (setting persisted).
- Bonus: in devtools, set
localStorage.settingsto a bogusringtoneIdand reload → it should fall back to Classic, not break.
A3. Incoming call uses the selected ringtone — 👥 2 people
Setup: Account A (you) and Account B in a DM or a private (invite-only) group room.
- As A, pick a non-silent ringtone (e.g. Chime).
- From B, start a call in that DM/room. Do not answer on A.
Expected on A
- The full-screen Incoming Call dialog appears (caller name, room avatar, Answer / Reject).
- The selected ringtone loops until you answer/reject/ignore (at the set volume).
- Answer → joins the call. Reject (DM) / Ignore (group) → dialog dismisses and ring stops.
- Set ringtone to Silent and repeat → dialog still appears, no sound.
A4. In-call banner for a second incoming call — 👥👥 (the trickiest one)
Setup: You (A) already in a call in Room 1. Account B can call you in a different Room 2 (a DM or private group you share). Ideally a third account C, or B leaves Room 1's call first.
- While A is actively in Room 1's call, trigger an incoming call to A from Room 2.
Expected on A
- No full-screen takeover. Instead a compact banner appears in the top-right corner with the caller's avatar, room name, "Incoming voice/video call", and Answer / Reject (or Ignore) buttons.
- It plays a single soft ping, not a looping ring (so it doesn't talk over your active call).
- The banner does not cover your active call's controls/PiP in a way that blocks them.
- Answer → switches you into Room 2's call. Reject/Ignore → banner disappears.
- The banner auto-dismisses if the caller hangs up / the call times out.
Also verify the no-op case: while in Room 1's call, if a notification for Room 1 itself arrives, nothing should pop up (no banner, no dialog).
A5. Camera focus during screenshare (#1) — 👥 2 people
Setup: You (A) and B in a call; B (or another participant) sharing their screen, and at least one person with camera on.
- As A, open the participant glance (the stacked avatars / member list for the call) and click a participant who has their camera on.
- In the menu, click "Focus camera".
Expected
- The view switches to spotlight and pins that person's camera tile, overriding the auto-spotlighted screenshare.
- It stays on that camera (doesn't immediately snap back to the screenshare).
- If you pick someone with their camera off, it should at worst just toggle spotlight (graceful fallback), not error.
A6. Avatar decorations on call tiles (#3) — 👥 2 people
Setup: A participant in the call has an avatar decoration set (Settings → Profile decoration).
- Join a call with that participant.
- Look at our participant roster / prescreen tiles (not the avatars rendered inside the Element Call video grid — those are EC's and out of scope).
Expected: the decoration ring/overlay renders around that participant's avatar on the call tile, the same way it does in member lists.
A7. EC iframe load watchdog + recovery UI (#EC)
This guards against a permanently-stuck "Loading…" call.
- Normal case: join a call → it should connect within a few seconds as usual (the watchdog stays invisible).
- Failure case (best-effort to reproduce): throttle your network hard (devtools → Network → Offline) right as you click join, or block the Element Call origin, so the iframe can't finish loading.
Expected
- On a genuine failure/timeout (~25s), instead of an endless spinner you get a visible error overlay with Retry / Leave buttons.
- Retry attempts to reload the call; Leave exits cleanly.
- Normal joins must not trigger the error overlay (no false positives) — this is the important part to confirm.
- Self-heal: if the error overlay appears on a slow network but EC then finishes loading anyway, the overlay should dismiss itself and drop you into the live call (it no longer strands you on the error screen). Worth confirming on a deliberately throttled-but-not-blocked connection.
B. Polls (N4) — render correctly on non-TDS themes
This was the actual bug: poll buttons used undefined CSS variables, so on the default (non-Lotus-Terminal) themes they rendered with invisible borders / no selected state.
B1. Poll renders on a default theme
- Switch to a default Cinny theme (Settings → Appearance — not Lotus Terminal / TDS). Test both a dark and a light theme.
- In any room, create a poll (composer → poll button): a single-choice poll with 3 options.
Expected
- Each option is a clearly bordered button with visible rounded corners.
- A radio circle indicator is visible on the left of each option.
- Text, and (after votes) the percentage, are legible.
B2. Voting + selected/progress state
- Vote on an option. Expected
- The selected option shows a filled accent border + filled radio, and an accent progress-bar fill grows behind it proportional to the vote %.
- The percentage and total vote count update.
- Click again / pick another option → selection moves correctly (single-choice replaces; the bar redraws).
B3. Multiple-choice poll
- Create a poll allowing multiple selections. Expected
- Indicators are square checkboxes (not circles); selected ones show a ✓ that's legible against the filled box.
- You can select several options; each shows its own progress fill.
B4. Lotus Terminal theme regression
- Switch to Lotus Terminal / TDS theme and re-open a poll. Expected: still looks correct (the fix uses theme tokens, so the TDS accent should now drive it) — no worse than before.
C. Robustness / background behavior
C1. Presence updates on tab close
- Open the app, then close the tab (or quit the browser).
- From another session/device, check your presence shortly after.
Expected: you go offline/away reliably (the unload now uses
fetch({keepalive})). Previously this could be missed.
C2. Upload retry on flaky network (best-effort)
- In devtools → Network, set a throttle that drops/slows requests, or toggle Offline briefly during a file upload. Expected
- A transient failure retries (up to 3×, with backoff) and the upload can still succeed once the network recovers.
- A genuine, permanent rejection (e.g. file too large / 4xx) still fails fast with the usual error — it should not spin retrying.
C3. General timeline/composer perf (no functional regression)
The memoization changes are invisible if correct. Just confirm nothing broke:
- Open a busy room; scrolling, jump-to-latest, mark-as-read all still work.
- Composer: send a message, upload a file, share a location, pick an emoji and a sticker — all still work.
D. Element Call 0.20.1 merge — regression sweep (👥 2 people)
The upstream bump changed EC's internals and DOM selectors; our call controls drive that iframe, so sweep them. In a live call with 2 people, confirm each of our control-bar buttons works:
- Mic mute/unmute (icon + actual audio)
- Camera on/off
- Deafen / Sound toggle (your deafen key too)
- Screenshare start/stop (and the "Share your screen?" confirm)
- Screenshare audio mute toggle
- Fullscreen toggle
- ⋮ More menu → Spotlight/Grid, Reactions, Settings each open the right EC panel
- End call leaves cleanly
- PTT (push-to-talk) if enabled: hold key = transmit, release = mute; releasing on blur works
- AFK auto-mute if enabled: goes muted after the timeout
- PiP (picture-in-picture) mini window: drag, resize, fullscreen button, return-to-call; the "You muted" / "All muted" badges show on the right person
- Denoise (if ML noise suppression enabled): call audio still flows, no silence
If any control does nothing, that usually means an EC DOM selector changed — capture the console and tell me which button.
Backlog of previously-fixed-but-unverified items
Sections A–D above are this session's work. Everything below was fixed in earlier waves and is still flagged ⚠️ UNTESTED in
LOTUS_BUGS.md/LOTUS_TODO.md. They're grouped by what kind of environment you need (mobile, desktop, screen reader, etc.) so you can knock out a whole category at once. None of these are urgent the way A–D are; do them as you have the right device handy.
E. Mobile / responsive (needs a real phone, or devtools device emulation)
E1. Composer toolbar touch targets (#7)
On a phone, open a room and the composer toolbar. Tap each button (attach, format, sticker, emoji, GIF, location, poll, schedule, send). Expected: every button is comfortably tappable (≥44×44px), no mis-taps hitting the wrong icon.
E2. Room Settings — no horizontal overflow (#8)
On a narrow phone screen, open Room Settings. Expected: the settings nav panel fills the full width; no horizontal scrollbar / sideways scrolling anywhere in the panel.
E3. Modals go fullscreen on mobile (#9)
On a phone, open several dialogs: Leave Room, Create Room, Create Space, Invite User, Report (room/user/message), Edit History, Forward Message, Remind Me, Schedule Message, Device Verification, Poll Creator. Expected: each opens fullscreen (no floating box, no rounded corners / max-width margins). On desktop the same modals should still be the normal centered boxes.
E4. Composer not hidden by the keyboard (#10) — iOS Safari especially
On a phone (priority: iOS Safari), tap into the composer so the on-screen keyboard appears. Expected: the composer input stays visible above the keyboard; the layout shrinks rather than the composer sliding under the keyboard.
E5. Mobile "Saved Messages" access (Mobile Bookmarks)
On a phone, inside a room, open the room header ··· More Options menu. Expected: a "Saved Messages" item is present; tapping it opens the bookmarks panel. (This was the only in-room access point missing on mobile.)
F. Visual / theming
F1. Animated chat background — no flicker (#2)
Settings → set an animated chat background (e.g. anim-rain / anim-aurora / anim-stars). Watch the message text and composer while it animates. Expected: smooth animation, no flickering / shimmering on message text or the composer, especially after scrolling. Note your GPU/browser if you see artifacts.
F2. Background vs. Seasonal theme are mutually exclusive (#6)
In Settings → Appearance:
- Pick a chat background → confirm any seasonal theme auto-switches off.
- Pick a seasonal theme → confirm the chat background auto-clears to none.
- (Edge) If you have old data with both set, after reload only one should visibly apply (no double-overlay clutter).
F3. Background / seasonal picker grid layout (N81)
In Settings → Appearance, look at the Chat Background and Seasonal Theme swatch grids; resize the window narrow→wide. Expected: swatches reflow to fill each row evenly (responsive grid), with no lopsided/orphaned last row at any width.
G. Calls — additional unverified (👥 2 people)
G1. PiP mute badges point at the right person (#12)
In a call with at least one other person, pop out the Picture-in-Picture mini window.
- You mute your own mic → a "You"/muted badge appears bottom-left (your status).
- A remote participant (or all of them) mutes → an "All muted" badge appears top-right (clearly about other people). Expected: the bottom-left badge is never triggered by someone else muting — that was the original bug (it looked like your own mic was muted when it wasn't).
G2. Full-screen camera broadcasts
- In a camera-only call (no screenshare), confirm the Fullscreen button is available (previously only showed during screenshare).
- Use MemberGlance → Focus camera to full-screen/spotlight a specific person's camera. (Overlaps A5; if you've done A5 you can skip.)
G3. PTT badge renders on all themes (N53)
Enable Push-to-talk (Settings → Calls) and join a call. Hold the PTT key. Expected: the floating PTT badge above the controls shows "PTT — Hold KEY" when idle and "● Live" (green) while held — on both a default theme and Lotus Terminal (it's now a single folds Chip; the old terminal-only variant was removed).
H. Media / performance (needs a room with many images)
H1. Lazy image decryption (P5-5 / MediaGallery)
Open a room / media gallery with many images (ideally encrypted). Scroll down through them. Expected: images decrypt/load as they approach the viewport, not all at once on open; scrolling stays smooth and memory doesn't balloon. Off-screen images shouldn't all decode up front.
H2. Thumbnail framing (P5-6)
Look at tall portrait images in the timeline and in the media gallery. Expected: thumbnails are framed center-top (so faces/subjects at the top aren't cropped out); no awkward stretching. Opening the full-size viewer still shows the whole image (contain, not cropped).
I. Accessibility (needs a screen reader: VoiceOver / NVDA / TalkBack)
With a screen reader on, navigate message hover-actions and content and confirm each control announces a meaningful label (not "button" / blank):
- Reaction buttons announce the emoji + count (e.g. "thumbsup reaction, 3 people").
- Edit history button announces "View edit history".
- Thread indicator announces "View thread".
- Reply (jump to original) announces "Jump to original message".
J. Desktop / Tauri build only
J1. Proactive update notifications (P5-40)
In the desktop (Tauri) build, with an update available, launch the app (and/or leave it running ~12h). Expected: an in-app toast/badge alerts you that an update is available, without manually checking Settings. (Needs an actual newer release to point at.)
J2. DTLN noise suppression sanity
In Settings → Calls, enable ML noise suppression with the DTLN model, then join a call. Expected: your mic audio still flows (no silence/robotic dropouts) and background noise is reduced. Confirmed working earlier but flagged for a final real-call check; verify on both web and desktop.
K. Features — end-to-end unverified
K1. Remind Me Later
On a message, ··· → Remind Me, pick a short preset (the 20-min one, or wait one out). Expected: when due, a Lotus toast fires linking to that message; the reminder then clears itself. Survives a reload while pending (stored in account data).
K2. Advanced search filters (P4-9)
In message search: use the sender picker (instead of typing from:@user), the date-range quick presets (Today / Last week / Last month / Last year), and the Has link toggle.
Expected: each narrows results correctly and reflects in the search.
K3. Notification content + click target (P5-20 partial)
Trigger a desktop/browser notification for a new message.
Expected: it shows the real message body (username: message, not "New inbox notification from…"); clicking it brings the window to front and navigates directly to that message (not just the inbox).
Priority if you're short on time
- A4 (in-call banner) + A3 (ringtone) — newest, most logic, hardest to reproduce.
- B1–B3 (polls on a default theme) — the confirmed visual bug.
- D (EC 0.20.1 control sweep) — guards against the upstream merge breaking calls.
- A7 false-positive check (normal joins don't show the error overlay).
- Everything else.