Step-by-Step Guide — Follow each step exactly as written. All values are provided — do not improvise.
TC-COMM-006: Rich-Text Compose & Send-Test (Detailed)
Module: Communications — Broadcasts (composer)
Primary Test User: comms@demo.membervu.com / Comms123! (Communications Manager)
Priority: P1
URLs for this test:
Frontend:
Broadcasts:
MailHog (email viewer):
Frontend:
https://stg-rcme.membervu.com/loginBroadcasts:
https://stg-rcme.membervu.com/admin/broadcastsMailHog (email viewer):
https://stg-webmail.membervu.com
What changed vs. the old TC pages: earlier Communications pages said "no test-send", "no merge tags", and "raw-HTML
<textarea> body". All three are now FALSE — the composer is a rich-text editor with an HTML-source toggle, merge tags resolve per-recipient, and a Send-Test button exists. Trust this page.
Step 1: Log in and open the composer
| Step | Action (EXACT clicks/typing) | Expected Result (EXACT text/behavior) | Test Value |
|---|---|---|---|
| 1 | Go to https://stg-rcme.membervu.com/login; sign in. | Dashboard loads. | comms@demo.membervu.com / Comms123! |
| 2 | Sidebar → Communications → Broadcasts; click New Broadcast (or the inline compose form). | Composer opens with Subject, Body, Audience <select>, Tags. | — |
| 3 | Set Subject. | Field accepts text. | Subject QA COMM-006 {{firstName}} |
Step 2: Compose with the rich-text editor (CM6-01)
| Step | Action | Expected Result | Test Value |
|---|---|---|---|
| 1 | In the Body editor, type a line, select it, click Bold (B). Add a second line, click Italic (I). | Text renders bold / italic in the editor. A formatting toolbar is present (this is NOT a plain textarea). | Hi member, welcome to RCME. |
| 2 | Select a word, click Link, enter a URL. | Word becomes a link. | https://rotaryclubmanila.org |
| 3 | Add a bulleted list (2 items) and a numbered list (2 items) via the toolbar. | Lists render with markers. | — |
| 4 | Save as Draft. | Broadcast saved, status DRAFT. | — |
Data assertion: the saved body (view via the edit form's HTML-source toggle, or the broadcast preview API) must contain real HTML tags —
<strong>, <em>, <a href>, <ul><li>, <ol><li> — and must NOT contain <script>, <iframe>, or any on*= event handler (server-side sanitizeBroadcastBody strips them regardless of authoring mode). If a <script> survives, that is a security FAIL.
Step 3: HTML-source toggle + lossy-conversion warning (CM6-02)
| Step | Action | Expected Result | Test Value |
|---|---|---|---|
| 1 | Click the Rich text ⇄ HTML toggle to switch to HTML source mode. | The editor now shows the raw HTML markup of your body (tags visible as text). | — |
| 2 | In HTML mode, paste a fragment containing a table and an image. | Raw HTML accepted in the source box. | <table><tr><td>A</td></tr></table><img src="x"> |
| 3 | Toggle back to Rich text mode. | A confirmation/warning appears before converting ("switching may lose formatting" — tables/images/headings Tiptap can't model). Cancel keeps HTML mode; Confirm converts and drops the unsupported nodes. | — |
Step 4: Sandboxed branded preview (CM6-03)
| Step | Action | Expected Result | Test Value |
|---|---|---|---|
| 1 | Click Preview. | A modal opens rendering the full branded email (tenant logo + header/footer bars), not just the raw body. | — |
| 2 | Right-click → Inspect the preview frame (or read the DOM). | It is an <iframe> with sandbox="allow-same-origin" and NO allow-scripts — so embedded script cannot run in the preview. | — |
| 3 | Compare the header/footer bar color to the tenant brand color. | Bar color equals the tenant's OrgProfile.primaryColor (RCME brand), NOT a hardcoded blue/purple. | — |
Step 5: Send-Test (CM6-04)
| Step | Action | Expected Result | Test Value |
|---|---|---|---|
| 1 | On the DRAFT broadcast, click Send Test (POST /api/broadcasts/:id/send-test). | Success toast; NO bulk send is triggered. | — |
| 2 | Open https://stg-webmail.membervu.com. | Exactly ONE new email. To = comms@demo.membervu.com (the requesting admin's own address) — NOT any member. Subject begins [TEST]. | — |
| 3 | Return to the Broadcasts list; inspect the broadcast row. | Still DRAFT. sentAt empty, recipient count unchanged — Send-Test does NOT consume/lock the broadcast. It remains editable. | — |
Step 6: Merge-tag substitution + XSS escape (CM6-05 / CM6-06)
This is a security assertion — do not skip. The point is that a member-controlled value (their name) containing markup must NOT be able to inject HTML/script into a broadcast delivered to other members.
| Step | Action | Expected Result | Test Value |
|---|---|---|---|
| 1 | As an admin, temporarily set a test member's first name to a script payload (Members → edit → First name). | Saved. | First name <script>alert(1)</script> |
| 2 | In the broadcast body, include a greeting with the merge tag. | Editor accepts it. | Hello {{firstName}} — {{unknownTag}} |
| 3 | Send-Test (or preview) with that member as the sample recipient, and view the delivered email source in webmail. | {{firstName}} is replaced with the member's name rendered as escaped text — you see literal <script>…, the alert does NOT fire, and there is no live <script> tag in the HTML. A normal member's name substitutes plainly (NOT double-escaped — a name like O'Brien shows as O'Brien). | — |
| 4 | Check the unsupported tag. | {{unknownTag}} is left inert in preview and stripped from the real send payload — recipients never see a literal {{unknownTag}}. | — |
| 5 | Revert the test member's first name. | Restored to the original value. | — |
Step 7: Segment-filter validation (CM6-07)
| Step | Action | Expected Result | Test Value |
|---|---|---|---|
| 1 | Create/edit a segment (or POST directly) with an unknown filter key or a Prisma-operator-shaped value. | Request rejected with 400 and a validation error — the filter is NOT silently ignored (which would blast the full audience). Only status / roles / membershipTypeId are valid keys. | Filter {"in":["ADMIN"]} or {"unpaidInvoices":true} |
CLEANUP
- Delete the QA COMM-006 draft broadcast.
- Confirm the test member's first name was reverted (Step 6.5) — do not leave a script payload in seed data.
- Delete any throwaway test segment created in Step 7.