Contacts
List Contacts
| ID | Test Case | Preconditions | Steps | Expected Result | Priority |
|---|---|---|---|---|---|
| CON-001 | View contacts list with pagination | Logged in as Agent, org has 5 contacts | 1. Go to /contacts 2. Observe the contacts tab is active | List displays all 5 contacts in rows with columns: phone, name, email, tags, opted_in status, lead indicator. Page size is 50 by default | High |
| CON-002 | Search contacts by name | Logged in as Agent, contacts exist: "John Smith", "Jane Doe", "Bob Johnson" | 1. Go to /contacts 2. Type "Jane" in search field 3. Press Enter or wait for auto-search | Only "Jane Doe" contact row appears in list. Phone, email, tags, and lead indicator displayed | High |
| CON-003 | Search contacts by phone | Logged in as Agent, contact with phone "+1234567890" exists | 1. Go to /contacts 2. Type "+1234567890" in search field | Contact row appears with matching phone. Name, email, tags, and lead indicator displayed | High |
| CON-004 | Filter contacts by tag | Logged in as Agent, contacts with tags: "vip", "lead", "customer" exist | 1. Go to /contacts 2. Click tag filter dropdown 3. Select "vip" | Only contacts with "vip" tag appear. Other tags still visible in dropdown | High |
| CON-005 | Pagination: navigate to next page | Logged in as Agent, 120 contacts exist (page size 50) | 1. Go to /contacts 2. Observe page 1 shows contacts 1–50 3. Click next page arrow | Page 2 displays contacts 51–100. Previous/next buttons enabled. Page counter shows "Page 2" | High |
| CON-006 | Pagination: navigate to previous page | Logged in as Agent, on page 2 of contacts | 1. Click previous page arrow | Page 1 displays. Previous button disabled (if on page 1). Next button enabled | High |
| CON-007 | Empty contacts list | Logged in as Agent, no contacts created yet | 1. Go to /contacts | Empty state message displays: "No contacts yet. Create your first contact" or similar. Create Contact button visible | High |
| CON-008 | Search with no results | Logged in as Agent, contacts exist but search term has no matches | 1. Go to /contacts 2. Type "nonexistent" in search field | Empty state displays: "No contacts match your search". Search field retains input | Medium |
| CON-009 | Filter by tag with no results | Logged in as Agent, tag filter exists but no contacts have that tag | 1. Go to /contacts 2. Select tag that no contacts have | Empty state displays. Tag filter dropdown still shows the tag | Medium |
| CON-010 | Clear search field | Logged in as Agent, search field has text "Jane" | 1. Go to /contacts 2. Click X button on search field (if present) OR clear text | All contacts reappear in list | Medium |
| CON-011 | Clear tag filter | Logged in as Agent, tag filter "vip" is active | 1. Go to /contacts with tag filter active 2. Click X on tag filter or select "All tags" | All contacts appear regardless of tags | Medium |
| CON-012 | Search and filter combined | Logged in as Agent, contacts exist: phone "+1234" tagged "vip", "+5678" tagged "lead" | 1. Go to /contacts 2. Enter "+1234" in search 3. Select "vip" tag filter | Only contact with phone "+1234" and tag "vip" displays | Medium |
| CON-100 | Contact list shows lead indicator | Logged in as Agent, contact "John" is a lead, contact "Jane" is not a lead | 1. Go to /contacts 2. Observe contact rows | Row for "John" shows lead badge/icon (e.g., "Lead" label or star). Row for "Jane" has no lead indicator | High |
| CON-101 | Lead indicator shows tooltip on hover | Logged in as Agent, contact row visible with lead indicator | 1. Hover over lead badge/icon on contact row | Tooltip appears: "This contact has an associated lead" or "Click to view lead" | Medium |
Create Contact
| ID | Test Case | Preconditions | Steps | Expected Result | Priority |
|---|---|---|---|---|---|
| CON-013 | Create contact with required fields only | Logged in as Agent, at /contacts | 1. Click "New Contact" or "+" button 2. Enter phone "+1234567890" 3. Click Save | Success toast: "Contact created". Modal closes. New contact appears in list with phone "+1234567890", name/email/tags blank, no lead indicator | High |
| CON-014 | Create contact with all fields | Logged in as Agent, at /contacts | 1. Click "New Contact" 2. Enter phone "+1234567890", name "John Doe", email "john@example.com", tags "vip,lead" 3. Click Save | Success toast appears. Contact row displays all values: phone "+1234567890", name "John Doe", email "john@example.com", tags ["vip","lead"], no lead indicator (until converted) | High |
| CON-015 | Create contact with JSON metadata | Logged in as Agent, at /contacts create modal | 1. Click "New Contact" 2. Enter phone "+1234567890" 3. Paste metadata JSON: `{"custom_field":"value"}` 4. Click Save | Contact created. Success toast shows. Metadata saved (visible when contact is edited) | Medium |
| CON-016 | Validation: phone field required | Logged in as Agent, at /contacts create modal | 1. Click "New Contact" 2. Leave phone empty 3. Click Save | Error message appears under phone field: "Phone number is required" or similar. Modal stays open | High |
| CON-017 | Validation: invalid phone format | Logged in as Agent, at /contacts create modal | 1. Click "New Contact" 2. Enter phone "invalid" (not a valid phone) 3. Click Save | Error message: "Invalid phone number format. Must start with + and contain digits" or similar | High |
| CON-018 | Validation: duplicate phone | Logged in as Agent, contact with phone "+1234567890" exists, at create modal | 1. Click "New Contact" 2. Enter phone "+1234567890" (existing) 3. Click Save | Error toast: "A contact with this phone number already exists" or 409 Conflict message | High |
| CON-019 | Validation: invalid email format | Logged in as Agent, at /contacts create modal | 1. Click "New Contact" 2. Enter phone "+1234567890", email "not-an-email" 3. Click Save | Error message under email field: "Invalid email format" or toast error. Contact not created | Medium |
| CON-020 | Create contact with tags (comma-separated input) | Logged in as Agent, at /contacts create modal | 1. Click "New Contact" 2. Enter phone "+1234567890", name "Jane" 3. In tags field, type "vip,lead,customer" 4. Click Save | Contact created with tags ["vip","lead","customer"]. Tags display as individual badges in list row | Medium |
| CON-021 | Create contact form: cancel without saving | Logged in as Agent, at create contact modal with form filled | 1. Click "New Contact" 2. Enter phone "+1234567890", name "John" 3. Click Cancel or X button | Modal closes. No contact created. List unchanged | Medium |
| CON-022 | Create contact: form validation on blur | Logged in as Agent, at create modal | 1. Click "New Contact" 2. Enter email "invalid-email" 3. Click outside email field (blur) | Error message appears under email field immediately (without clicking Save) | Low |
View / Edit Contact
| ID | Test Case | Preconditions | Steps | Expected Result | Priority |
|---|---|---|---|---|---|
| CON-023 | Open contact details modal | Logged in as Agent, contact "John Doe" (+1234567890) exists | 1. Go to /contacts 2. Click on contact row for "John Doe" | Modal or detail view opens showing: phone, name, email, tags, opted_in toggle, metadata, created_at, updated_at, assigned_user/team, lead_id (if contact is a lead) | High |
| CON-024 | Edit contact: change name | Logged in as Agent, contact "John Doe" exists, detail view open | 1. Click Edit or Pencil icon 2. Change name to "Jane Doe" 3. Click Save | Success toast: "Contact updated". Modal closes. List row now shows "Jane Doe" as name | High |
| CON-025 | Edit contact: change email | Logged in as Agent, editing contact with email "old@example.com" | 1. Click Edit 2. Change email to "new@example.com" 3. Click Save | Success toast. Contact email updated to "new@example.com" in list and detail view | High |
| CON-026 | Edit contact: add/remove tags | Logged in as Agent, editing contact with tags ["vip"] | 1. Click Edit 2. Add tag "customer" 3. Click Save | Success toast. Contact now shows tags ["vip","customer"]. Tag removed similarly | High |
| CON-027 | Edit contact: update metadata JSON | Logged in as Agent, editing contact with metadata | 1. Click Edit 2. Modify metadata JSON field 3. Click Save | Success toast. Metadata persisted (visible in detail view) | Medium |
| CON-028 | Edit contact: cannot change phone | Logged in as Agent, editing contact | 1. Click Edit 2. Try to change phone field | Phone field is disabled/read-only. Cannot edit phone number | High |
| CON-029 | Edit contact: toggle opted_in status | Logged in as Agent, editing contact with is_opted_in=false | 1. Click Edit 2. Click toggle switch for "Opted In" 3. Click Save | Success toast. Contact opted_in status toggled to true in list/detail view | Medium |
| CON-030 | Edit contact: validation on empty name | Logged in as Agent, editing contact, name is currently "John" | 1. Click Edit 2. Clear name field 3. Click Save | Contact saves successfully (name is optional). Name becomes null in display | Medium |
| CON-031 | Edit contact: validation on invalid email | Logged in as Agent, editing contact | 1. Click Edit 2. Enter email "invalid" 3. Click Save | Error message: "Invalid email format" under email field | Medium |
| CON-032 | Edit contact form: cancel without saving | Logged in as Agent, editing contact | 1. Click Edit 2. Change name to "New Name" 3. Click Cancel | Modal closes. Contact name remains unchanged in list | Medium |
| CON-033 | View contact: open detail view from list | Logged in as Agent, contact row visible | 1. Click contact row 2. Observe detail modal | Detail view shows all contact info: phone, name, email, tags, opted_in, timestamps, assigned_user/team, lead_id (if lead) | High |
| CON-034 | View contact 404 | Logged in as Agent, contact ID "invalid-id" | 1. Manually navigate to /contacts/invalid-id OR contact was deleted 2. Observe | Error message: "Contact not found" or 404 page | Low |
| CON-102 | Contact detail shows lead ID and is_lead flag | Logged in as Agent, contact "John" is a lead, detail view open | 1. Open contact detail for "John" 2. Observe response data or UI | Detail view shows lead_id (UUID of associated lead) and is_lead=true. If not a lead, lead_id is null and is_lead=false | High |
Delete Contact
| ID | Test Case | Preconditions | Steps | Expected Result | Priority |
|---|---|---|---|---|---|
| CON-035 | Delete contact | Logged in as Agent, contact "John Doe" exists | 1. Go to /contacts 2. Right-click or find delete option on contact row 3. Click Delete or Trash icon 4. Confirm delete | Success toast: "Contact deleted". Contact row disappears from list | High |
| CON-036 | Delete contact: confirmation modal | Logged in as Agent, attempting to delete contact | 1. Click Delete/Trash icon on contact 2. Observe confirmation modal | Confirmation modal appears: "Delete contact? This action cannot be undone." with Cancel and Confirm buttons | High |
| CON-037 | Delete contact: cancel delete | Logged in as Agent, confirmation modal open for delete | 1. Click Cancel button in confirmation modal | Modal closes. Contact remains in list | Medium |
| CON-038 | Delete contact: soft delete (audit trail) | Logged in as Agent, contact deleted | 1. Delete contact 2. Go to contact audit log | Audit log entry shows: event_type="contact_deleted", actor=current user, timestamp | Medium |
Assign Contact
| ID | Test Case | Preconditions | Steps | Expected Result | Priority |
|---|---|---|---|---|---|
| CON-039 | Assign contact to user | Logged in as Agent, contact "John Doe" exists, org members include "Agent Bob" | 1. Go to /contacts 2. Open contact detail 3. Click "Assign to User" or assign icon 4. Select "Agent Bob" 5. Click Save | Success toast: "Contact assigned to Agent Bob". Detail view shows "Assigned to: Agent Bob". Audit log records actor_id who made the assignment | High |
| CON-040 | Assign contact to team | Logged in as Agent, contact exists, teams exist: "Sales Team" | 1. Open contact detail 2. Click assign option 3. Select team "Sales Team" 4. Click Save | Success toast: "Contact assigned to Sales Team". assigned_team_id populated. Audit log records actor_id of assigning user | High |
| CON-041 | Unassign contact from user | Logged in as Agent, contact assigned to "Agent Bob" | 1. Open contact detail 2. Click assign option 3. Clear/remove user assignment 4. Click Save | Success toast. Contact assigned_user_id becomes null. "Assigned to" no longer shown. Audit log records actor_id | Medium |
| CON-042 | Assign to user vs team priority | Logged in as Agent, contact can be assigned to both user and team | 1. Assign contact to both user "Agent Bob" and team "Sales Team" 2. Observe detail view | Both assigned_user_id and assigned_team_id are populated. Both shown in UI. Audit log records actor_id for assignment changes | Medium |
| CON-099 | Assign contact: audit log shows actor | Logged in as Agent A, Agent B assigns contact to Agent C | 1. Agent B assigns contact to "Agent C" 2. Agent A opens contact audit log | Audit log entry shows "Contact assigned to Agent C", actor_name="Agent B" (the person who made the assignment, recorded via actor_id) | High |
Import Contacts
| ID | Test Case | Preconditions | Steps | Expected Result | Priority |
|---|---|---|---|---|---|
| CON-043 | Import contacts from CSV | Logged in as Agent, at /contacts | 1. Click Import or Upload button 2. Select CSV file with columns: phone, name, email, tags, opted_in 3. Observe progress | Upload modal shows. File accepted. "Processing..." or similar indicator | High |
| CON-044 | Import CSV: successful creation | Logged in as Agent, CSV file with 3 valid rows uploaded | 1. Upload CSV with rows: (+1111111111, John, john@ex.com, vip, true), (+2222222222, Jane, jane@ex.com, lead, true), (+3333333333, Bob, bob@ex.com, "", false) 2. Wait for completion | Success toast: "Imported 3 contacts (0 updated, 0 skipped, 0 errors)". All 3 contacts appear in list | High |
| CON-045 | Import CSV: skip duplicate phones | Logged in as Agent, contact with phone "+1111111111" exists, CSV has same phone | 1. Upload CSV with duplicate phone "+1111111111" 2. Wait for completion | Result shows: "Imported 0 contacts (1 updated, 0 skipped)" or "1 skipped". Existing contact not duplicated | High |
| CON-046 | Import CSV: update existing contact | Logged in as Agent, contact "+1111111111" with name "Old Name" exists, CSV has same phone with name "New Name" | 1. Upload CSV with row: (+1111111111, New Name, newemail@ex.com, tag, true) 2. Wait | Result: "1 updated". Contact name changes to "New Name". Import result dialog shows updated count | High |
| CON-047 | Import CSV: validation errors | Logged in as Agent, CSV has invalid rows: no phone, invalid email | 1. Upload CSV with 3 rows: 1 valid, 1 no phone, 1 invalid email 2. Wait | Result: "Imported 1 (0 updated, 0 skipped, 2 errors)". Error details shown: row numbers and error messages | High |
| CON-048 | Import CSV: empty file | Logged in as Agent, empty CSV uploaded | 1. Upload empty CSV 2. Wait | Error message: "CSV file is empty or has no valid rows" or result shows "0 imported" | Medium |
| CON-049 | Import CSV: missing required column | Logged in as Agent, CSV missing "phone" column | 1. Upload CSV without phone column 2. Wait | Error message: "Missing required column: phone" or import fails with validation error | High |
| CON-050 | Import CSV: preview before import | Logged in as Agent, CSV file selected | 1. Click Import 2. Preview modal shows first 5-10 rows | Preview displays file content with column headers. User can confirm before final import | Medium |
| CON-051 | Import CSV: cancel import | Logged in as Agent, import in progress or preview open | 1. Click Cancel button | Upload canceled. No contacts imported. Return to contacts list | Medium |
Export Contacts
| ID | Test Case | Preconditions | Steps | Expected Result | Priority |
|---|---|---|---|---|---|
| CON-052 | Export all contacts to CSV | Logged in as Agent, 5 contacts exist | 1. Go to /contacts 2. Click Export or Download button | CSV file downloaded with filename "contacts.csv". Columns: phone, name, email, tags, opted_in. All 5 contact rows present | High |
| CON-053 | Export with search filter applied | Logged in as Agent, 5 contacts exist, search "John" returns 2 contacts | 1. Go to /contacts 2. Search "John" 3. Click Export | CSV downloaded contains only the 2 filtered contacts, not all 5 | High |
| CON-054 | Export with tag filter applied | Logged in as Agent, filter by tag "vip" shows 3 contacts | 1. Go to /contacts 2. Filter by tag "vip" 3. Click Export | CSV downloaded contains only the 3 "vip" tagged contacts | High |
| CON-055 | Export empty contacts list | Logged in as Agent, no contacts created | 1. Go to /contacts 2. Click Export | CSV file downloaded with headers only (phone, name, email, tags, opted_in) and no data rows | Medium |
| CON-056 | Export file format validation | Logged in as Agent, contacts exported | 1. Export contacts 2. Open CSV file in text editor | File is valid CSV format: comma-separated, quoted strings, newlines between rows | Low |
Contact Audit Log
| ID | Test Case | Preconditions | Steps | Expected Result | Priority |
|---|---|---|---|---|---|
| CON-057 | View contact audit log | Logged in as Agent, contact "John Doe" exists with history | 1. Open contact detail 2. Click "Audit Log" or "Activity" tab | Audit log displays list of events: "Contact created", "Tag added 'vip'", etc. Each entry shows timestamp, actor name, event description | High |
| CON-058 | Audit log: contact created event | Logged in as Agent, contact was just created | 1. Open contact detail 2. View audit log | First entry shows: event_type="contact_created", actor_name="current_user", text="Contact created via {source}", created_at=timestamp | Medium |
| CON-059 | Audit log: tag added event | Logged in as Agent, tag "vip" was added to contact | 1. Open contact detail 2. View audit log | Entry shows: event_type="tag_added", text="Tag 'vip' added", actor_name, timestamp | Medium |
| CON-060 | Audit log: tag removed event | Logged in as Agent, tag "vip" was removed from contact | 1. Open contact detail 2. View audit log | Entry shows: event_type="tag_removed", text="Tag 'vip' removed", actor_name, timestamp | Medium |
| CON-061 | Audit log: contact updated event | Logged in as Agent, contact name was changed from "John" to "Jane" | 1. Open contact detail 2. View audit log | Entry shows: event_type="contact_updated" or similar, text contains old/new values, actor_name, timestamp | Medium |
| CON-062 | Audit log: pagination/load more | Logged in as Agent, contact has 100+ audit log entries | 1. Open contact detail 2. View audit log 3. Scroll to bottom | "Load More" button appears at bottom. Click to fetch next 50 entries. New entries append to list | Medium |
| CON-063 | Audit log: time formatting | Logged in as Agent, viewing audit log entries | 1. Open contact detail 2. View audit log | Recent entries show "just now", "5m ago", "2h ago". Older entries show date format "Mar 15, 2026" | Low |
| CON-064 | Add note to contact | Logged in as Agent, contact detail open, audit log visible | 1. In audit log section, click "Add Note" or text area 2. Type "Follow up next week" 3. Click Save Note | Success toast. New entry appears at top of audit log: event_type="note_added", text="Follow up next week", actor_name=current_user | High |
| CON-065 | Edit note on contact | Logged in as Agent, contact has note "Old text" in audit log | 1. Find note entry in audit log 2. Click Edit or Pencil icon on note 3. Change text to "New text" 4. Click Save | Success toast. Note text updated. Entry shows "(edited)" or timestamp updated_at differs from created_at | High |
| CON-066 | Delete note on contact | Logged in as Agent, contact has note in audit log | 1. Find note entry 2. Click Delete or Trash icon 3. Confirm delete | Success toast. Note entry removed from audit log | High |
| CON-067 | Audit log: actor names | Logged in as Agent, audit log has entries from multiple users | 1. Open contact detail 2. View audit log | Each entry shows actor_name (user's full name), not user ID. If actor is system, shows "System" or similar | Medium |
| CON-068 | Audit log: lead-related events | Logged in as Agent, contact was converted to lead | 1. Open contact audit log 2. Observe events | Log shows events like "lead_created", "lead_stage_changed", "lead_converted" with relevant data | Medium |
| CON-069 | Audit log: conversation events | Logged in as Agent, contact has messages | 1. Open contact audit log 2. Observe events | Log shows "conversation_created", "conversation_resolved", "conversation_assigned to {user}" events | Medium |
| CON-070 | Audit log: reminder events | Logged in as Agent, reminders were set on contact | 1. Open contact audit log 2. Observe events | Log shows "reminder_scheduled for {due_at}", "reminder_sent to {notified_user}" events with formatted date/time | Medium |
Contact Leads Integration
| ID | Test Case | Preconditions | Steps | Expected Result | Priority |
|---|---|---|---|---|---|
| CON-071 | Convert contact to lead | Logged in as Agent, contact "John Doe" exists, at /contacts?tab=contacts | 1. Open contact detail 2. Click "Convert to Lead" or similar button 3. Confirm conversion | Success toast: "Contact converted to lead" or "Lead created". Contact list row now shows lead indicator. Audit log shows "lead_created" event | High |
| CON-072 | Convert to lead: specify source | Logged in as Agent, converting contact to lead | 1. Click "Convert to Lead" 2. Select source: "manual", "import", "form", etc. 3. Confirm | Lead created with source populated. Audit log shows "Lead created (manual)" or similar. Contact row shows lead indicator | Medium |
| CON-073 | Convert contact to lead: audit trail | Logged in as Agent, contact converted to lead | 1. Open contact audit log 2. Observe recent events | Audit log shows "lead_created" event with source data, actor_name=current_user | Medium |
| CON-074 | View leads tab | Logged in as Agent, at /contacts | 1. Click "Leads" tab next to "Contacts" | Leads tab active. List shows leads (contacts with lead records) with lead-specific columns: stage, score, source, etc. | High |
Leads Tab
| ID | Test Case | Preconditions | Steps | Expected Result | Priority |
|---|---|---|---|---|---|
| CON-075 | Switch between Contacts and Leads tabs | Logged in as Agent, at /contacts?tab=contacts | 1. Click Leads tab 2. Observe leads list 3. Click Contacts tab | Each tab maintains its own view. Switching tabs does not reset search/filter. Tab state persisted in URL | High |
| CON-076 | Leads tab: view lead details | Logged in as Agent, on Leads tab, lead exists | 1. Click lead row | Lead detail modal opens showing: contact info, lead stage, lead score, source, created_at, associated contact | High |
| CON-077 | Leads tab: update lead stage | Logged in as Agent, lead in Leads tab with stage "qualified" | 1. Open lead detail 2. Click stage dropdown 3. Select "negotiation" 4. Click Save | Success toast. Lead stage updated to "negotiation". Audit log shows "Lead stage: qualified → negotiation" | High |
| CON-078 | Leads tab: update lead score | Logged in as Agent, editing lead with score 50 | 1. Open lead detail 2. Change score to 75 3. Click Save | Success toast. Lead score updated. Audit log shows "Lead score: 50 → 75" | Medium |
| CON-079 | Leads tab: mark lead as lost | Logged in as Agent, lead detail open | 1. Click "Mark as Lost" or similar button 2. Enter reason "Budget constraints" 3. Click Confirm | Success toast. Lead status changed to "lost". Audit log shows "Lead marked lost: Budget constraints". Lead removed from active leads list | High |
| CON-080 | Leads tab: convert lead to customer | Logged in as Agent, lead detail open | 1. Click "Convert to Customer" or similar button 2. Confirm | Success toast: "Lead converted". Lead status changed. Audit log shows "Lead converted". Lead may move to customers view | Medium |
| CON-081 | Leads tab: delete lead | Logged in as Agent, lead in leads tab | 1. Click Delete/Trash icon on lead 2. Confirm delete | Success toast: "Lead deleted". Lead row removed. Audit log shows "Lead deleted" event. Contact remains in contacts list | High |
Permission Boundaries
| ID | Test Case | Preconditions | Steps | Expected Result | Priority |
|---|---|---|---|---|---|
| CON-082 | Agent cannot delete contact (if role-based) | Logged in as Agent, contact exists | 1. Go to /contacts 2. Attempt to click Delete/Trash icon on contact | If delete not allowed for Agents: Delete button disabled or hidden. Tooltip says "Permission denied" | High |
| CON-083 | Agent can view all contacts | Logged in as Agent | 1. Go to /contacts | Agent can see all contacts in organization, including those assigned to other agents | High |
| CON-084 | Agent cannot view contacts from other orgs | Logged in as Agent in Org A, contact exists in Org B | 1. Attempt to access /contacts or contact ID from Org B | 404 error or "Contact not found". Cannot access cross-org contacts | High |
| CON-085 | Admin can manage all contact operations | Logged in as Admin | 1. Go to /contacts 2. Create, edit, delete, import, export, assign contacts | All operations available. No permission restrictions | High |
Real-time Updates (WebSocket)
| ID | Test Case | Preconditions | Steps | Expected Result | Priority |
|---|---|---|---|---|---|
| CON-086 | Contact created by another user appears in list | Logged in as Agent A at /contacts, Agent B creates contact in same org | 1. Agent B creates contact "New Contact" 2. Agent A observes contacts list | New contact appears in Agent A's list without page refresh. WebSocket event triggers update. lead_id and is_lead fields initialized | Medium |
| CON-087 | Contact edited by another user updates in list | Logged in as Agent A viewing contact detail, Agent B edits same contact | 1. Agent B changes contact name from "John" to "Jane" 2. Agent A observes detail view | Contact name updates to "Jane" in Agent A's view without refresh. lead_id and is_lead fields updated if changed | Medium |
| CON-088 | Contact deleted by another user removed from list | Logged in as Agent A at /contacts, Agent B deletes contact | 1. Agent B deletes contact visible to Agent A 2. Agent A observes list | Contact row disappears from Agent A's list without refresh | Medium |
| CON-103 | Contact converted to lead updates lead indicator in real-time | Logged in as Agent A at /contacts, Agent B converts contact to lead | 1. Agent B converts contact "John" to lead 2. Agent A observes contacts list | Contact row for "John" now shows lead indicator (badge/icon) without page refresh. lead_id and is_lead fields updated | Medium |
Error Handling
| ID | Test Case | Preconditions | Steps | Expected Result | Priority |
|---|---|---|---|---|---|
| CON-089 | Network error on create contact | Logged in as Agent, network disconnected during create | 1. Click "New Contact" 2. Enter data 3. Click Save while network is down | Error toast: "Network error. Please try again" or "Failed to save contact" | Medium |
| CON-090 | Network error on list contacts | Logged in as Agent, network disconnected | 1. Go to /contacts 2. Observe loading state | Loading spinner shows briefly. Error message: "Failed to load contacts. Please refresh." with retry button | Medium |
| CON-091 | Timeout on import | Logged in as Agent, large CSV uploaded (10k+ rows) | 1. Upload large CSV 2. Wait for timeout | Timeout message after 30s (or configured timeout). User can retry or cancel | Medium |
| CON-092 | Concurrent edit conflict | Logged in as Agent A editing contact, Agent B edits same contact simultaneously | 1. Agent A changes name to "Name A" 2. Agent B changes name to "Name B" and saves first 3. Agent A clicks Save | Agent A sees conflict message: "Contact was modified by another user. Please refresh and try again." Last-write-wins or merge strategy applied | Low |
UI / UX Behaviors
| ID | Test Case | Preconditions | Steps | Expected Result | Priority |
|---|---|---|---|---|---|
| CON-093 | Form validation on input focus | Logged in as Agent, at create contact form | 1. Click email field 2. Type "invalid" 3. Click outside (blur) | Error message appears under email field immediately (without Save click) | Low |
| CON-094 | Save button disabled until form valid | Logged in as Agent, at create contact form | 1. Observe Save button with no phone entered | Save button is disabled (greyed out) until phone field filled with valid format | Low |
| CON-095 | Unsaved changes warning | Logged in as Agent, editing contact form with changes | 1. Click Edit contact 2. Change name 3. Attempt to close modal without Save | Modal asks: "Discard unsaved changes?" with Cancel and Discard buttons | Low |