# TipTap Migration Testing Strategy
## Overview
This document outlines the comprehensive testing strategy for the TipTap Markdown migration. The strategy uses a combination of **Vitest** for pure function unit tests and **Cypress Component Testing** for TipTap-dependent components, leveraging the project's existing test infrastructure.
---
## Component Overview
The TipTap migration includes the following core components:
| Component | Description | Test Tool |
|-----------|-------------|-----------|
| `lib/src/Components/TipTap/utils/preprocessMarkdown.ts` | 6-stage preprocessing pipeline | Vitest |
| `lib/src/Components/TipTap/utils/simpleMarkdownToHtml.tsx` | Static HTML conversion | Vitest |
| `lib/src/Components/TipTap/extensions/Hashtag.tsx` | Custom extension with tokenizer | Cypress Component |
| `lib/src/Components/TipTap/extensions/ItemMention.tsx` | Custom extension with tokenizer | Cypress Component |
| `lib/src/Components/TipTap/extensions/VideoEmbed.tsx` | Block element for videos | Cypress Component |
| `lib/src/Components/Input/RichTextEditor.tsx` | Main editor component | Cypress Component |
| `lib/src/Components/Map/Subcomponents/ItemPopupComponents/TextView.tsx` | Read-only editor | Cypress Component |
| `lib/src/Components/Map/Subcomponents/ItemPopupComponents/TextViewStatic.tsx` | Lightweight static renderer | Vitest |
| `lib/src/Utils/ReplaceURLs.ts` | URL/email processing utilities | Vitest |
---
## Testing Pyramid Architecture
```
┌─────────────────────┐
│ E2E Tests │ 3-5 critical user journeys
│ (Cypress E2E) │
└──────────┬──────────┘
│
┌───────────────┴───────────────┐
│ Cypress Component Tests │ TipTap extensions + editors
│ Real browser, no mocking │ Contract tests
└───────────────┬───────────────┘
│
┌──────────────────────────┴──────────────────────────┐
│ Vitest Unit Tests │
│ preprocessMarkdown, simpleMarkdownToHtml │
│ Pure functions, security tests │
└──────────────────────────────────────────────────────┘
```
### Rationale
1. **Vitest Unit Tests for Pure Functions (Primary Focus)**
- `preprocessMarkdown.ts` and `simpleMarkdownToHtml.tsx` are **pure functions** without DOM dependencies
- Extremely fast execution, high coverage achievable
- Easy to maintain and debug
- Contains most of the **business logic** for markdown processing
- Includes **security/XSS tests** for HTML output
2. **Cypress Component Tests for TipTap Extensions**
- TipTap requires a **real browser environment** (jsdom mocking is fragile and incomplete)
- The project already has Cypress Component Testing configured (`lib/cypress.config.ts`)
- Real browser provides native support for `Range`, `Selection`, `ResizeObserver`, etc.
- Test Markdown ↔ JSON ↔ HTML roundtrips with actual TipTap editor
- **Contract tests** verify preprocessing output is valid TipTap input
3. **E2E Tests Only for Critical User Journeys**
- Uses existing Cypress E2E setup (`cypress/`)
- Leverages existing custom commands (`cy.clickMarker()`, `cy.waitForPopup()`)
- For smoke tests and regression protection
---
## Component Usage Context
Understanding where each component is used guides test priority:
| Context | Component | Rendering | Priority |
|---------|-----------|-----------|----------|
| **Map Popup** | `TextViewStatic` | `simpleMarkdownToHtml` (static HTML) | P0 - most visible |
| **Item Card** | `TextViewStatic` | `simpleMarkdownToHtml` (static HTML) | P0 - list views |
| **Item Profile** | `TextView` | TipTap editor (read-only) | P1 - detail view |
| **Item Edit Form** | `RichTextEditor` | TipTap editor (editable) | P0 - data integrity |
---
## Test Setup
### Vitest Configuration (`lib/setupTest.ts`)
For **pure function unit tests**, no TipTap-specific mocks are needed:
```typescript
import '@testing-library/jest-dom'
```
> **Note:** TipTap editor tests use Cypress Component Testing instead of Vitest to avoid fragile jsdom mocks. This provides a real browser environment where `Range`, `Selection`, `ResizeObserver`, and other DOM APIs work natively.
### Cypress Component Testing (`lib/cypress.config.ts`)
Already configured in the project:
```typescript
import { defineConfig } from 'cypress'
export default defineConfig({
component: {
devServer: {
framework: 'react',
bundler: 'vite',
},
specPattern: ['**/**/*.cy.{ts,tsx}'],
},
})
```
### Running Tests
```bash
# Vitest unit tests
cd lib && npm run test:unit
# Cypress component tests (interactive)
cd lib && npx cypress open --component
# Cypress component tests (headless)
cd lib && npx cypress run --component
# Cypress E2E tests
cd cypress && npm test
```
---
## Detailed Test Cases
### 1. Unit Tests: `preprocessMarkdown.ts`
#### A) `convertNakedUrls` (internal function)
| Category | Test Case | Input | Expected Output |
|----------|-----------|-------|-----------------|
| **Happy Path** | Basic URL | `"Check https://example.com out"` | `"Check [example.com](https://example.com) out"` |
| **Happy Path** | Remove www | `"https://www.example.com"` | `"[example.com](https://example.com)"` |
| **Happy Path** | Multiple URLs | `"https://a.com and https://b.com"` | Both converted |
| **Happy Path** | URL with query params | `"https://example.com?a=1&b=2"` | Full URL preserved in link |
| **Skip** | URL in markdown link | `"[link](https://example.com)"` | Unchanged |
| **Skip** | URL in autolink | `"code` |
| **Happy Path** | External link | `"[text](https://x.com)"` | `` |
| **Happy Path** | Internal link | `"[profile](/profile)"` | `` (no target) |
| **Happy Path** | Headers H1-H6 | `"# Title"` ... `"###### Sub"` | Corresponding h1-h6 tags |
| **Happy Path** | Blockquote | `"> quote"` | `quote
` |
| **Happy Path** | Paragraph break | `"Para1\n\nPara2"` | `
` |
| **Happy Path** | Line break | `"Line1\nLine2"` | `
` |
| **Happy Path** | Video embed | `