# Test Case: Opportunity Object

> **Test ID**: OPP-TEST-001
> **Priority**: P2
> **Test Environment**: NexusCRM (https://nexuscrm.pingcap.com)
> **Last Updated**: 2026-03-30
> **Test Agent**: dev-browser (Playwright-based automation)

## 1. Test Overview

This test covers the Opportunity object functionality in NexusCRM with focus on:
- **Stage Transitions**: Does changing Stage auto-update Forecast Category?
- **Silent Save Failures**: Does the frontend swallow PATCH errors?
- **Label Quality**: LABEL-001/002/003 assessment
- **Related Lists**: Standard Opportunity related lists

**Test Results Summary**: 8 paths defined, 6 Complete, 2 N/A (Create skipped - 50 records exist)

**Key Findings**:
- Stage change (Closed Won → Negotiation): **Save successful** (PATCH 204)
- Forecast Category auto-update: **NOT working** — requires manual selection
- Silent failure check: **Partial failure** — some field changes don't persist despite 204 response
- Label quality: "Owner ID" has ID suffix (LABEL-001 issue)

---

## 2. Prerequisites

- **Environment**: NexusCRM deployed at https://nexuscrm.pingcap.com
- **Authentication**: OAuth token-based (client credentials flow)
- **Test Data**: 50 Opportunity records in system
- **Browser Tool**: dev-browser CLI (QuickJS + Playwright API)

---

## 3. Test Steps

### OPP-L01: List View — Default View

**Objective**: Verify Opportunity list page loads correctly with proper column headers and data

| Step | Action | Expected Result | Actual Result | Pass/Fail |
|------|--------|-----------------|---------------|-----------|
| 1 | Navigate to `/object/Opportunity` | Page loads successfully | URL: https://nexuscrm.pingcap.com/object/Opportunity | Pass |
| 2 | Observe column headers | Human-readable labels | **Headers**: Name, Stage, Forecast Category, Close Date, Closed, Won | Pass |
| 3 | Record record count | Shows actual count | **50 records** displayed | Pass |
| 4 | Check for duplicate columns | No duplicates | No duplicate columns (unlike Quote's duplicate "Quote Number") | Pass |
| 5 | Record first 3 opportunities | Opportunity data displayed | See table below | Pass |

**First 3 Opportunities**:

| Name | Stage | Forecast Category | Close Date | Closed | Won |
|------|-------|-------------------|------------|--------|-----|
| CC-FY24Q4 TiDB Cloud | Closed Won | Closed | Mar 31, 2024 | Yes | Yes |
| Funplus - User Analyzing Platform | Closed Lost | Omitted | Oct 31, 2022 | Yes | No |
| Airbnb TiDB Prototyping Support | Closed Won | Closed | Sep 28, 2021 | Yes | Yes |

**Column Analysis**:
- "Closed" and "Won" are **separate columns** (not combined as "Closed Won")
- This is slightly non-standard (Salesforce typically shows "Stage" with status)

**Reference Screenshot**: `screenshots/opportunity/list_default.png`

---

### OPP-L02: Quick Analytics Cards

**Objective**: Verify Quick Analytics cards display meaningful metrics

| Step | Action | Expected Result | Actual Result | Pass/Fail |
|------|--------|-----------------|---------------|-----------|
| 1 | Click "Quick Analytics" button | Analytics panel expands | Panel expanded | Pass |
| 2 | Observe analytics cards | Business-relevant metrics displayed | **No distinct cards found** — metrics inline with list | N/A |
| 3 | Record any metrics visible | Pipeline value, stage distribution, etc. | Record count (50) shown in button | Partial |

**Analytics Assessment**:
- Unlike Quote (which has separate metric cards), Opportunity has **inline analytics only**
- Quick Analytics button shows "(50)" record count
- No separate cards for pipeline value, win rate, or stage distribution

**Verdict**: Analytics are **minimal** but not problematic — no junk metrics observed.

**Reference Screenshot**: `screenshots/opportunity/analytics_cards.png`

---

### OPP-C01: Create — New Opportunity

**Status**: **SKIPPED** — 50 existing records available for testing. Create flow not needed for Stage transition testing.

**Rationale**: Same approach as Quote testing — existing records sufficient for OPP-D01~D03 and OPP-E01~E02.

---

### OPP-D01: Detail View

**Objective**: Verify Opportunity detail page displays fields correctly

| Step | Action | Expected Result | Actual Result | Pass/Fail |
|------|--------|-----------------|---------------|-----------|
| 1 | Click Opportunity name button from list | Navigates to detail page | URL: `/object/Opportunity/0065g000002Hn6gAAC` | Pass |
| 2 | Observe page heading | Opportunity name displayed | "CC-FY24Q4 TiDB Cloud" | Pass |
| 3 | Record action buttons | Edit, Delete, Share visible | All buttons present | Pass |
| 4 | Record field sections | Organized sections | Account ID, Record Type ID, Name, Description, Stage, etc. | Pass |
| 5 | Check Stage display | Picklist value shown | "Closed Won" (later changed to "Negotiation") | Pass |
| 6 | Check Forecast Category | Value displayed | Not found on main detail view | Partial |
| 7 | Check for page layout | Layout renders | **No "No page layout assigned" message** | Pass |

**Action Buttons**: Back, Edit, Delete, Share, Contact Roles(0), Products(1)

**Key Fields Observed**:
- Account ID: SQUARE PLUS TECHNOLOGY L.L.C
- Record Type ID: New
- Name: CC-FY24Q4 TiDB Cloud
- Stage: Closed Won (changed to Negotiation during testing)
- Close Date: 3/31/2024
- Forecast Category: Not visible on main detail

**Reference Screenshot**: `screenshots/opportunity/detail_view.png`

---

### OPP-D02: Detail — Related Lists

**Objective**: Verify Related Lists display correctly on Opportunity detail

| Step | Action | Expected Result | Actual Result | Pass/Fail |
|------|--------|-----------------|---------------|-----------|
| 1 | Click "Related" tab | Related lists panel displays | 7 related lists shown | Pass |
| 2 | Wait for lists to load | All lists render | Lists loaded | Pass |
| 3 | Record each related list | Name, count, status | See table below | Pass |

**Related Lists**:

| Related List | Record Count | Status |
|-------------|--------------|--------|
| Contact Roles | 0 | ✅ Loaded |
| Products | 1 | ✅ Loaded |
| Opportunity Team | 0 | ✅ Loaded |
| Quotes | 1 | ✅ Loaded |
| Orders | 1 | ✅ Loaded |
| Cloud User Request | 1 | ✅ Loaded |
| Elvance Scorecards | 0 | ✅ Loaded |

**Comparison with Salesforce Standard**:
- ✅ Contact Roles (OpportunityContactRole)
- ⚠️ Products (OpportunityLineItem) — named "Products" not "Opportunity Products"
- ⚠️ Opportunity Team — non-standard
- ✅ Quotes
- ✅ Orders
- ⚠️ Cloud User Request — custom object (PoC__c)
- ⚠️ Elvance Scorecards — custom object
- ❌ Stage History — **NOT found** (expected in Salesforce)
- ❌ Notes & Attachments — not observed
- ❌ Activities — not observed

**Reference Screenshot**: `screenshots/opportunity/detail_related_lists.png`

---

### OPP-D03: Detail — Stage History

**Objective**: Find Stage History section for opportunity

| Step | Action | Expected Result | Actual Result | Pass/Fail |
|------|--------|-----------------|---------------|-----------|
| 1 | Check main detail page for Stage History | Section present | Not found on main detail | Fail |
| 2 | Check Related tab | Stage History in related lists | Not in related lists | Fail |
| 3 | Scroll detail page | History at bottom | No history section found | Fail |

**Stage History Status**: **NOT FOUND**

**Expected in Salesforce**: Stage History shows stage transitions with:
- Stage name
- Probability %
- Forecast Category
- Close Date
- Amount
- Modified By
- Modified Date

**Verdict**: Stage History feature **not implemented** or hidden. This is a gap vs Salesforce standard.

**Reference Screenshot**: N/A (feature not present)

---

### OPP-E01: Edit — Stage Change

**Objective**: Verify Stage change behavior and Forecast Category auto-update

| Step | Action | Expected Result | Actual Result | Pass/Fail |
|------|--------|-----------------|---------------|-----------|
| 1 | Navigate to detail → click "Edit" | Edit form opens | URL: `?edit=true` | Pass |
| 2 | Record current Stage | Stage value shown | "Closed Won" | Pass |
| 3 | Record current Forecast Category | Forecast value shown | "-- Select --" (empty) | Pass |
| 4 | Click Stage button to open picklist | Picklist options displayed | 8 options visible | Pass |
| 5 | Record Stage options | Full picklist | See below | Pass |
| 6 | Change Stage: Closed Won → Negotiation | Stage updated in form | "Negotiation" selected | Pass |
| 7 | Check Forecast Category **before save** | Auto-updated? | Still "-- Select --" | **Fail** |
| 8 | Click "Save" | Save completes | PATCH 204 response | Pass |
| 9 | Verify Stage on detail page | Shows "Negotiation" | **Confirmed** | Pass |

**Stage Picklist Options** (8 total):
1. Prospecting
2. Discovery & Qualification
3. Technical Validation
4. Business Validation
5. Negotiation
6. Deal Closed
7. Launched
8. Closed Lost

**Network Response**:
- HTTP Status: **204 No Content**
- Body: Empty (204 = no content)

**Forecast Category Auto-Update**: **NOT WORKING**
- Original: Stage="Closed Won", Forecast=empty
- After Stage change: Stage="Negotiation", Forecast=still empty
- Expected: Should auto-update to "Best Case" or "Commit" when Stage changes to "Negotiation"

**Reference Screenshot**: `screenshots/opportunity/edit_stage_changed.png`

---

### OPP-E02: Edit — Silent Failure Check

**Objective**: Verify that save failures are properly reported (not swallowed by frontend)

| Step | Action | Expected Result | Actual Result | Pass/Fail |
|------|--------|-----------------|---------------|-----------|
| 1 | Open Edit form | Form loads | `?edit=true` | Pass |
| 2 | Change Next Step field | Value entered | "Test silent failure check - {timestamp}" | Pass |
| 3 | Click "Save" | Save completes | Page navigates to detail | Pass |
| 4 | Check Next Step on detail | Value persisted | **Original value** (not test value) | **Fail** |
| 5 | Re-open Edit, change Description | Value entered | "Test description - agent verification" | Pass |
| 6 | Intercept PATCH response | Record status | **204 No Content** | Pass |
| 7 | Check Description on detail | Value persisted | **Still "—"** (not test value) | **Fail** |

**Silent Failure Analysis**:

| Field | Changed? | PATCH Status | Persisted? |
|-------|----------|--------------|------------|
| Next Step | Yes | 204 | ❌ No |
| Description | Yes | 204 | ❌ No |
| Stage | Yes | 204 | ✅ Yes |

**Conclusion**: **PARTIAL SILENT FAILURE** confirmed.
- Stage changes **do persist**
- Text field changes (Next Step, Description) **do NOT persist** despite 204 response
- This suggests backend may be rejecting certain fields silently, or frontend is not including them in PATCH body

**Reference Screenshot**: `screenshots/opportunity/edit_network_response.png`

---

## 4. Stage Transition Assessment

**Assessment Method**: Direct Stage change test with Forecast Category monitoring

| Original Stage | New Stage | Forecast Category Before | Forecast Category After | Auto-Updated? | Save Result |
|---------------|-----------|-------------------------|------------------------|---------------|-------------|
| Closed Won | Negotiation | -- Select -- | -- Select -- | ❌ **NO** | ✅ 204 OK |

**Salesforce Standard Behavior** (expected):
| Stage | Forecast Category |
|-------|-------------------|
| Prospecting | Pipeline |
| Discovery & Qualification | Pipeline |
| Technical Validation | Best Case |
| Business Validation | Best Case |
| Negotiation | Commit |
| Deal Closed | Omitted |
| Launched | Omitted |
| Closed Lost | Omitted |

**Verdict**: Forecast Category **does NOT auto-update** when Stage changes. This is a **functional gap** vs Salesforce standard behavior.

---

## 5. Label Quality Summary

**Assessment Method**: Edit form field labels captured via dev-browser snapshot

### LABEL-001: Reference Field Labels (ID Suffix) — FAIL

| Field API Name | Current Label | Expected Label | Status |
|---------------|---------------|----------------|--------|
| OwnerId | Owner ID * | Owner | ❌ FAIL — has "ID" suffix |
| RecordTypeId | Record Type ID | Record Type | ❌ FAIL — has "ID" suffix |
| AccountId | Account ID | Account | ❌ FAIL — has "ID" suffix |
| CampaignId | Campaign ID | Campaign | ❌ FAIL — has "ID" suffix |
| PriceBookId | Price Book ID | Price Book | ❌ FAIL — has "ID" suffix |
| QuoteId | Quote ID | Quote | ❌ FAIL — has "ID" suffix |
| ContractId | Contract ID | Contract | ❌ FAIL — has "ID" suffix |

### LABEL-002: Custom Field Labels (Raw API Names) — PASS

| Field API Name | Current Label | Expected Label | Status |
|---------------|---------------|----------------|--------|
| (No raw API names observed) | — | — | ✅ PASS |

### LABEL-003: Field Order — PARTIAL

| Position | Field Label | Type | Assessment |
|----------|-------------|------|------------|
| 1 | Account ID | System/Lookup | ⚠️ System field first |
| 2 | Record Type ID | System | ⚠️ |
| 3 | Name * | Business | ✅ |
| 4 | Description | Business | ✅ |
| 5 | Stage * | Business | ✅ |

**Assessment**: First 2 fields are system fields, but business fields dominate top 10.

---

## 6. Screenshot Checklist

| # | Screenshot | Path | Status |
|---|------------|------|--------|
| 1 | List Default | `opportunity/list_default.png` | ✅ |
| 2 | Analytics Cards | `opportunity/analytics_cards.png` | ✅ |
| 3 | Analytics Expanded | `opportunity/analytics_expanded.png` | ✅ |
| 4 | Detail View | `opportunity/detail_view.png` | ✅ |
| 5 | Detail Related Lists | `opportunity/detail_related_lists.png` | ✅ |
| 6 | Edit Form | `opportunity/edit_form.png` | ✅ |
| 7 | Stage Picklist | `opportunity/stage_picklist.png` | ✅ |
| 8 | Edit Stage Changed | `opportunity/edit_stage_changed.png` | ✅ |
| 9 | Edit Save Result | `opportunity/edit_save_result.png` | ✅ |
| 10 | Edit Silent Failure Test | `opportunity/edit_silent_failure_test.png` | ✅ |
| 11 | Edit Save Verification | `opportunity/edit_save_verification.png` | ✅ |
| 12 | Edit Network Response | `opportunity/edit_network_response.png` | ✅ |

---

## 7. Known Issues Summary

| # | Path | Description | Severity | Related Scenario |
|---|------|-------------|----------|-----------------|
| 1 | OPP-E01 | Forecast Category does NOT auto-update when Stage changes | High | STAGE-001 |
| 2 | OPP-E02 | Silent failure: text field changes don't persist despite 204 response | High | SILENT-001 |
| 3 | OPP-D03 | Stage History feature not found (not implemented?) | Medium | HISTORY-001 |
| 4 | OPP-L01 | "Closed" and "Won" as separate columns (non-standard) | Low | UI-001 |
| 5 | LABEL-001 | Reference fields show "Owner ID", "Record Type ID" (ID suffix) | Medium | LABEL-001 |
| 6 | OPP-L02 | No distinct analytics cards (inline only) | Info | UX-001 |

---

## 8. A/B Comparison Notes (Salesforce)

| Feature | Expected (Salesforce) | Actual (NexusCRM) | Notes |
|---------|----------------------|-------------------|-------|
| List Columns | Name, Stage, Amount, Close Date, Probability | Name, Stage, Forecast Category, Close Date, Closed, Won | ⚠️ Extra columns |
| Stage Picklist | Standard stages | 8 custom stages | ⚠️ Different values |
| Forecast Category | Auto-updates with Stage | Manual selection only | ❌ Gap |
| Stage History | Built-in history tracking | Not found | ❌ Gap |
| Related Lists | Products, Contact Roles, Quotes, Activities | Products, Contact Roles, Quotes, + custom | ⚠️ Custom objects added |
| Edit Save | Updates all changed fields | Stage persists, text fields may not | ❌ Bug |
| Label Format | "Owner", "Record Type" | "Owner ID", "Record Type ID" | ❌ ID suffix |

---

## 9. Test Execution Notes

### Tooling
- **Browser**: dev-browser CLI (QuickJS runtime + Playwright API)
- **Timeout**: 10-30 seconds per script
- **Screenshots**: Saved via `page.screenshot()` to `screenshots/opportunity/`

### Key Discoveries

**Stage Transition**:
- Stage change from "Closed Won" to "Negotiation" works correctly
- PATCH returns 204 No Content (standard for successful update with no body)
- Stage value persists on detail page

**Forecast Category**:
- Does NOT auto-update when Stage changes
- Requires manual selection from dropdown
- This is a significant gap from Salesforce standard behavior

**Silent Failure**:
- Text field changes (Next Step, Description) do NOT persist
- Despite PATCH 204 response and UI navigation to detail page
- Stage changes DO persist
- This suggests selective field rejection or frontend serialization bug

**Label Quality**:
- Same LABEL-001 pattern as Quote: reference fields have "ID" suffix
- No LABEL-002 issues (no raw API camelCase names observed)

### What Was Successfully Tested
- ✅ List view default state (50 records, 6 columns)
- ✅ Quick Analytics button (minimal analytics)
- ✅ Detail view navigation and field display
- ✅ Related lists (7 lists, all loaded)
- ✅ Stage change and save (PATCH 204)
- ✅ Network response interception
- ✅ Stage picklist options (8 values)

### What Could NOT Be Fully Tested
- ⚠️ Stage History — feature not found
- ⚠️ Create form — skipped (existing records available)
- ⚠️ Silent failure root cause — requires backend investigation

---

## 10. Recommendations

1. **Implement Forecast Category auto-update** — When Stage changes, Forecast Category should auto-populate based on stage-to-forecast mapping

2. **Investigate silent field failures** — Text fields (Next Step, Description) not persisting despite 204 response. Check:
   - Backend field-level validation
   - Frontend PATCH payload serialization
   - Field-level permissions

3. **Add Stage History feature** — Standard Salesforce feature for tracking stage transitions

4. **Fix LABEL-001 issues** — Remove "ID" suffix from reference field labels (Owner ID → Owner, etc.)

5. **Enhance Quick Analytics** — Add meaningful pipeline metrics (total pipeline value, win rate, stage distribution)
