# Design Document: Mermaid 图表支持

## Overview

本设计文档描述了在 Argon WordPress 主题中集成 Mermaid 图表支持的技术方案。由于 WP-Markdown 编辑器的特殊渲染方式（将 Mermaid 代码块保存为单行，缺少真正的换行符），直接集成 Mermaid 存在技术障碍。

本设计采用**插件兼容方案**，通过支持主流 Mermaid WordPress 插件（如 WP Githuber MD、Markdown Block 等）来实现功能，同时提供主题级别的样式优化、夜间模式适配和性能优化。

### 核心设计原则

1. **插件优先**：依赖成熟的 Mermaid 插件处理代码解析和渲染
2. **主题增强**：提供样式优化、主题适配和性能优化
3. **灵活配置**：支持 CDN/本地加载、多种主题、调试模式
4. **优雅降级**：加载失败时提供备用方案和友好提示
5. **性能优先**：按需加载、异步加载、缓存优化

## Architecture

### 系统架构图

```
┌─────────────────────────────────────────────────────────────┐
│                     WordPress 前端页面                        │
└─────────────────────────────────────────────────────────────┘
                              │
                              ├─ 包含 Mermaid 代码块?
                              │
                    ┌─────────┴─────────┐
                    │                   │
                   是                  否
                    │                   │
                    ▼                   ▼
         ┌──────────────────┐    ┌──────────┐
         │  加载 Mermaid 库  │    │  不加载   │
         └──────────────────┘    └──────────┘
                    │
                    ├─ CDN 模式 / 本地模式
                    │
                    ▼
         ┌──────────────────┐
         │  Mermaid.js 库   │
         └──────────────────┘
                    │
                    ▼
         ┌──────────────────┐
         │  代码块检测器     │
         │  - class="mermaid"│
         │  - language="mermaid"│
         │  - data-lang="mermaid"│
         └──────────────────┘
                    │
                    ▼
         ┌──────────────────┐
         │  渲染引擎         │
         │  - 初始化配置     │
         │  - 主题适配       │
         │  - 错误处理       │
         └──────────────────┘
                    │
                    ▼
         ┌──────────────────┐
         │  样式增强器       │
         │  - 容器样式       │
         │  - 响应式适配     │
         │  - 夜间模式       │
         └──────────────────┘
                    │
                    ▼
         ┌──────────────────┐
         │  渲染后的 SVG     │
         └──────────────────┘
```

### 组件交互流程

```
用户访问页面
    │
    ▼
WordPress 渲染页面
    │
    ▼
主题检测页面内容
    │
    ├─ 是否包含 Mermaid 代码块?
    │
    ▼ (是)
加载 Mermaid 库 (CDN/本地)
    │
    ▼
DOMContentLoaded 事件触发
    │
    ▼
初始化 Mermaid 配置
    │
    ├─ 设置主题 (日间/夜间)
    ├─ 设置安全级别
    └─ 设置错误处理
    │
    ▼
检测所有 Mermaid 代码块
    │
    ▼
批量渲染图表
    │
    ├─ 成功 → 应用样式增强
    └─ 失败 → 显示错误提示
    │
    ▼
监听主题切换事件
    │
    ▼
重新渲染图表 (如需要)
```


## Components and Interfaces

### 1. 配置管理组件 (Configuration Manager)

**职责**：管理 Mermaid 相关的所有配置选项

**接口**：
```php
// 获取配置选项
function argon_get_mermaid_option($option_name, $default = null)

// 保存配置选项
function argon_update_mermaid_option($option_name, $value)

// 验证 CDN 地址格式
function argon_validate_mermaid_cdn_url($url)

// 获取当前主题模式对应的 Mermaid 主题
function argon_get_mermaid_theme()
```

**配置选项**：
- `argon_enable_mermaid`: 启用/禁用 Mermaid 支持 (true/false)
- `argon_mermaid_cdn_source`: CDN 来源 (jsdelivr/unpkg/custom/local)
- `argon_mermaid_cdn_custom_url`: 自定义 CDN 地址
- `argon_mermaid_theme`: 图表主题 (default/dark/forest/neutral/auto)
- `argon_mermaid_use_local`: 使用本地镜像 (true/false)
- `argon_mermaid_debug_mode`: 调试模式 (true/false)

### 2. 库加载器 (Library Loader)

**职责**：负责检测页面内容并按需加载 Mermaid 库

**接口**：
```php
// 检测页面是否包含 Mermaid 代码块
function argon_has_mermaid_content($content)

// 加载 Mermaid 库
function argon_enqueue_mermaid_scripts()

// 获取 Mermaid 库 URL
function argon_get_mermaid_library_url()
```

**实现逻辑**：
1. 在 `wp_enqueue_scripts` 钩子中检查当前页面内容
2. 使用正则表达式检测 Mermaid 代码块标记
3. 如果检测到，根据配置加载对应的库文件
4. 添加 async 或 defer 属性实现异步加载

**CDN 地址映射**：
```php
$cdn_urls = [
    'jsdelivr' => 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js',
    'unpkg' => 'https://unpkg.com/mermaid@10/dist/mermaid.min.js',
    'local' => get_template_directory_uri() . '/assets/vendor/mermaid/mermaid.min.js'
];
```

### 3. 渲染引擎初始化器 (Render Engine Initializer)

**职责**：初始化 Mermaid 配置并启动渲染

**接口**：
```javascript
// 初始化 Mermaid 配置
function initMermaidConfig()

// 获取当前主题对应的 Mermaid 主题
function getMermaidTheme()

// 渲染所有 Mermaid 图表
function renderAllMermaidCharts()

// 重新渲染图表（主题切换时）
function reRenderMermaidCharts()
```

**Mermaid 配置对象**：
```javascript
{
    startOnLoad: false,  // 手动控制渲染时机
    theme: 'default',    // 根据页面主题动态设置
    securityLevel: 'loose',  // 允许 HTML 标签
    logLevel: 'error',   // 生产环境使用 error，调试模式使用 debug
    flowchart: {
        useMaxWidth: true,
        htmlLabels: true
    }
}
```

### 4. 代码块检测器 (Code Block Detector)

**职责**：识别页面中的 Mermaid 代码块

**接口**：
```javascript
// 检测所有 Mermaid 代码块
function detectMermaidBlocks()

// 检查元素是否为 Mermaid 代码块
function isMermaidBlock(element)

// 提取代码块内容
function extractMermaidCode(element)
```

**检测规则**（优先级从高到低）：
1. `<div class="mermaid">` - 标准格式
2. `<pre><code class="language-mermaid">` - Markdown 格式
3. `<pre data-lang="mermaid">` - 自定义属性格式
4. `<code class="mermaid">` - 简化格式

**特殊处理**：
- 忽略 HTML 注释中的代码块
- 处理 WP-Markdown 生成的 `<script>document.write()</script>` 格式
- 解码转义字符（`\n`, `\"`, `\'`）

### 5. 样式增强器 (Style Enhancer)

**职责**：为渲染后的图表添加主题样式

**接口**：
```javascript
// 应用容器样式
function applyMermaidContainerStyles(container)

// 应用响应式样式
function applyResponsiveStyles(container)

// 应用夜间模式样式
function applyDarkModeStyles(container, isDarkMode)
```

**CSS 样式类**：
```css
.mermaid-container {
    background: var(--card-background);
    border-radius: 8px;
    padding: 20px;
    margin: 20px 0;
    box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    overflow-x: auto;
    max-width: 100%;
}

.mermaid-container svg {
    max-width: 100%;
    height: auto;
}

html.darkmode .mermaid-container {
    background: var(--card-background-dark);
    box-shadow: 0 2px 8px rgba(0,0,0,0.3);
}
```

### 6. 错误处理器 (Error Handler)

**职责**：处理渲染错误并显示友好提示

**接口**：
```javascript
// 处理渲染错误
function handleMermaidError(error, element)

// 显示错误提示
function showErrorMessage(element, errorInfo)

// 记录调试信息
function logDebugInfo(message, data)
```

**错误提示格式**：
```html
<div class="mermaid-error">
    <div class="error-icon">⚠️</div>
    <div class="error-title">Mermaid 图表渲染失败</div>
    <div class="error-message">错误类型: 语法错误</div>
    <div class="error-details">行号: 3</div>
    <details>
        <summary>查看原始代码</summary>
        <pre><code>...</code></pre>
    </details>
</div>
```

### 7. 主题切换监听器 (Theme Switch Listener)

**职责**：监听主题模式切换并重新渲染图表

**接口**：
```javascript
// 监听主题切换事件
function listenThemeSwitch()

// 主题切换回调
function onThemeSwitched(isDarkMode)

// 批量重新渲染
function batchReRender(elements)
```

**实现方式**：
- 监听 Argon 主题的 `argon:theme-switched` 自定义事件
- 监听 `html` 元素的 `darkmode` class 变化（MutationObserver）
- 使用防抖避免频繁重新渲染

### 8. 插件兼容层 (Plugin Compatibility Layer)

**职责**：检测并兼容主流 Mermaid 插件

**接口**：
```php
// 检测已安装的 Mermaid 插件
function argon_detect_mermaid_plugins()

// 检查是否已加载 Mermaid 库
function argon_is_mermaid_loaded()

// 避免重复加载
function argon_prevent_duplicate_loading()
```

**支持的插件**：
1. **WP Githuber MD** - 检测 `wp-githuber-md` 插件
2. **Markdown Block** - 检测 Gutenberg Mermaid 块
3. **Code Syntax Block** - 检测代码高亮插件的 Mermaid 支持

**兼容策略**：
- 如果插件已加载 Mermaid 库，主题不再重复加载
- 主题只提供样式增强和主题适配
- 通过 `window.mermaid` 对象检测库是否已加载


## Data Models

### 1. Mermaid 配置对象

```javascript
interface MermaidConfig {
    enabled: boolean;           // 是否启用
    cdnSource: string;          // CDN 来源: 'jsdelivr' | 'unpkg' | 'custom' | 'local'
    customCdnUrl: string;       // 自定义 CDN 地址
    theme: string;              // 图表主题: 'default' | 'dark' | 'forest' | 'neutral' | 'auto'
    useLocal: boolean;          // 是否使用本地镜像
    debugMode: boolean;         // 调试模式
    autoThemeSwitch: boolean;   // 自动切换主题
}
```

### 2. 代码块元素对象

```javascript
interface MermaidBlock {
    element: HTMLElement;       // DOM 元素
    code: string;               // Mermaid 代码
    type: string;               // 代码块类型: 'div' | 'pre-code' | 'custom'
    rendered: boolean;          // 是否已渲染
    error: Error | null;        // 渲染错误
}
```

### 3. 渲染结果对象

```javascript
interface RenderResult {
    success: boolean;           // 是否成功
    svg: string;                // 渲染后的 SVG
    error: {
        type: string;           // 错误类型
        message: string;        // 错误信息
        line: number;           // 错误行号
    } | null;
}
```

### 4. 插件检测结果

```php
interface PluginDetectionResult {
    'wp-githuber-md': boolean;      // WP Githuber MD
    'markdown-block': boolean;      // Markdown Block
    'code-syntax-block': boolean;   // Code Syntax Block
    'mermaid-loaded': boolean;      // Mermaid 库是否已加载
}
```

### 5. 错误信息对象

```javascript
interface ErrorInfo {
    type: string;               // 错误类型: 'syntax' | 'render' | 'load'
    message: string;            // 错误信息
    line: number | null;        // 错误行号
    code: string;               // 原始代码
    timestamp: number;          // 时间戳
}
```

## Correctness Properties

*属性是一种特征或行为，应该在系统的所有有效执行中保持为真——本质上是关于系统应该做什么的正式陈述。属性作为人类可读规范和机器可验证正确性保证之间的桥梁。*

### Property 1: 按需加载库

*对于任意* WordPress 页面，当且仅当页面内容包含 Mermaid 代码块时，主题应该加载 Mermaid JavaScript 库。

**Validates: Requirements 1.1, 1.5, 8.1**

### Property 2: CDN 地址正确性

*对于任意* CDN 配置选项（jsdelivr、unpkg、custom、local），生成的脚本 URL 应该与配置选项对应的 CDN 地址匹配。

**Validates: Requirements 1.2, 1.3**

### Property 3: 代码块识别完整性

*对于任意* 包含 Mermaid 标记的 HTML 元素（class="mermaid"、language="mermaid"、data-lang="mermaid"），检测器应该能够识别并提取其中的 Mermaid 代码。

**Validates: Requirements 10.1, 10.2, 10.3**

### Property 4: 渲染成功后替换内容

*对于任意* 成功渲染的 Mermaid 图表，原始代码块文本应该被移除，并替换为渲染后的 SVG 图表。

**Validates: Requirements 2.4**

### Property 5: 错误时保留原始代码

*对于任意* 渲染失败的 Mermaid 代码块，系统应该显示错误提示信息，并保留原始代码块以便用户修正。

**Validates: Requirements 7.1, 7.4**

### Property 6: 主题模式自动切换

*对于任意* 页面主题模式切换（日间↔夜间），当配置为自动切换时，所有 Mermaid 图表应该重新渲染并使用对应的图表主题（浅色↔深色）。

**Validates: Requirements 4.1, 4.2, 4.3**

### Property 7: 自定义主题优先级

*对于任意* 图表，当管理员设置了自定义图表主题时，应该使用自定义主题而不是根据页面主题自动切换。

**Validates: Requirements 4.5**

### Property 8: 响应式容器宽度

*对于任意* 渲染后的 Mermaid 图表容器，其最大宽度应该设置为 100%，并且当图表宽度超过容器时应该启用横向滚动。

**Validates: Requirements 3.1, 3.3**

### Property 9: 移动端自适应

*对于任意* 屏幕宽度小于 768px 的设备，Mermaid 图表应该自动调整大小以适应屏幕宽度，不应该出现横向溢出。

**Validates: Requirements 3.2**

### Property 10: 夜间模式样式适配

*对于任意* Mermaid 图表容器，在夜间模式下应该应用深色背景和边框样式，与页面整体风格保持一致。

**Validates: Requirements 6.5**

### Property 11: 卡片内边距

*对于任意* 在卡片中显示的 Mermaid 图表，容器应该添加适当的内边距（padding），确保图表与卡片边缘有足够的间距。

**Validates: Requirements 6.3**

### Property 12: CDN 地址验证

*对于任意* 用户输入的自定义 CDN 地址，保存前应该验证其格式是否为有效的 URL，并且以 `.js` 结尾。

**Validates: Requirements 5.5**

### Property 13: 避免重复加载

*对于任意* 页面，当检测到已有 Mermaid 插件加载了 Mermaid 库时，主题不应该重复加载该库。

**Validates: Requirements 9.4**

### Property 14: 错误信息完整性

*对于任意* Mermaid 解析错误，错误提示信息应该包含错误类型和详细的错误描述，帮助用户定位问题。

**Validates: Requirements 7.3**

### Property 15: 批量渲染性能

*对于任意* 包含多个 Mermaid 图表的页面，所有图表应该在一次 DOM 遍历中批量收集，然后批量渲染，而不是逐个渲染。

**Validates: Requirements 8.4**

### Property 16: 渲染缓存

*对于任意* 已成功渲染的 Mermaid 图表，在页面生命周期内不应该重复渲染，除非主题模式发生切换。

**Validates: Requirements 8.3**

### Property 17: 代码块优先级

*对于任意* 同时包含多个 Mermaid 标记的元素（如同时有 class="mermaid" 和 data-lang="mermaid"），应该优先使用 class 属性进行识别。

**Validates: Requirements 10.4**

### Property 18: 忽略注释代码块

*对于任意* 被 HTML 注释包裹的 Mermaid 代码块，检测器应该忽略它们，不进行渲染。

**Validates: Requirements 10.5**

## Error Handling

### 1. 库加载失败

**场景**：CDN 不可用或网络问题导致 Mermaid 库加载失败

**处理策略**：
1. 监听脚本 `onerror` 事件
2. 在控制台输出详细错误信息
3. 尝试降级到备用 CDN（jsdelivr → unpkg → local）
4. 如果所有 CDN 都失败，显示全局提示信息

**实现**：
```javascript
function loadMermaidWithFallback(urls, index = 0) {
    if (index >= urls.length) {
        console.error('[Argon Mermaid] 所有 CDN 加载失败');
        showGlobalError('Mermaid 库加载失败，请检查网络连接');
        return;
    }
    
    const script = document.createElement('script');
    script.src = urls[index];
    script.async = true;
    
    script.onerror = () => {
        console.warn(`[Argon Mermaid] CDN ${urls[index]} 加载失败，尝试备用 CDN`);
        loadMermaidWithFallback(urls, index + 1);
    };
    
    script.onload = () => {
        console.log(`[Argon Mermaid] 成功从 ${urls[index]} 加载库`);
        initMermaid();
    };
    
    document.head.appendChild(script);
}
```

### 2. 代码解析错误

**场景**：Mermaid 代码语法错误导致解析失败

**处理策略**：
1. 捕获 Mermaid 渲染异常
2. 提取错误类型和行号信息
3. 在原代码块位置显示友好的错误提示
4. 保留原始代码供用户查看和修正
5. 在调试模式下输出详细堆栈信息

**错误提示 UI**：
```html
<div class="mermaid-error-container">
    <div class="error-header">
        <span class="error-icon">⚠️</span>
        <span class="error-title">图表渲染失败</span>
    </div>
    <div class="error-body">
        <p class="error-type">错误类型: 语法错误</p>
        <p class="error-message">Expecting 'NEWLINE', 'SPACE', got 'GRAPH'</p>
        <p class="error-line">位置: 第 3 行</p>
    </div>
    <details class="error-code">
        <summary>查看原始代码</summary>
        <pre><code class="language-mermaid">...</code></pre>
    </details>
</div>
```

### 3. 配置验证错误

**场景**：管理员输入无效的配置选项

**处理策略**：
1. 在保存前验证所有配置项
2. CDN URL 格式验证（必须是有效 URL 且以 .js 结尾）
3. 主题名称验证（必须是预定义的主题之一）
4. 显示具体的验证错误信息
5. 阻止保存无效配置

**验证函数**：
```php
function argon_validate_mermaid_settings($settings) {
    $errors = [];
    
    // 验证 CDN URL
    if ($settings['cdn_source'] === 'custom') {
        $url = $settings['custom_cdn_url'];
        if (!filter_var($url, FILTER_VALIDATE_URL)) {
            $errors[] = 'CDN 地址格式无效';
        } elseif (!preg_match('/\.js$/', $url)) {
            $errors[] = 'CDN 地址必须以 .js 结尾';
        }
    }
    
    // 验证主题名称
    $valid_themes = ['default', 'dark', 'forest', 'neutral', 'auto'];
    if (!in_array($settings['theme'], $valid_themes)) {
        $errors[] = '无效的图表主题';
    }
    
    return $errors;
}
```

### 4. 插件冲突

**场景**：多个插件同时加载 Mermaid 库导致冲突

**处理策略**：
1. 在加载前检测 `window.mermaid` 是否已存在
2. 如果已存在，跳过库加载，只应用样式增强
3. 记录检测结果到控制台
4. 在设置页显示插件兼容性状态

**检测逻辑**：
```javascript
function checkMermaidLoaded() {
    if (typeof window.mermaid !== 'undefined') {
        console.log('[Argon Mermaid] 检测到 Mermaid 库已由其他插件加载');
        return true;
    }
    return false;
}
```

### 5. 主题切换异常

**场景**：主题切换时重新渲染失败

**处理策略**：
1. 使用 try-catch 包裹重新渲染逻辑
2. 如果重新渲染失败，保留原有图表
3. 在控制台输出警告信息
4. 不影响页面其他功能

**实现**：
```javascript
function reRenderOnThemeSwitch() {
    const charts = document.querySelectorAll('.mermaid-rendered');
    
    charts.forEach(chart => {
        try {
            const code = chart.dataset.mermaidCode;
            const newTheme = getMermaidTheme();
            
            mermaid.initialize({ theme: newTheme });
            mermaid.render('mermaid-' + Date.now(), code, (svg) => {
                chart.innerHTML = svg;
            });
        } catch (error) {
            console.warn('[Argon Mermaid] 重新渲染失败，保留原图表', error);
        }
    });
}
```


## Testing Strategy

### 测试方法概述

本功能采用**双重测试策略**：
- **单元测试**：验证具体示例、边缘情况和错误条件
- **属性测试**：验证跨所有输入的通用属性

两者互补且都是全面覆盖所需的：
- 单元测试捕获具体的 bug
- 属性测试验证一般正确性

### 单元测试策略

单元测试应专注于：
- **具体示例**：演示正确行为的特定案例
- **集成点**：组件之间的交互
- **边缘情况和错误条件**：特殊场景处理

**测试框架**：使用 PHPUnit（PHP 部分）和 Jest（JavaScript 部分）

**PHP 单元测试示例**：
```php
// 测试 CDN URL 验证
public function test_validate_cdn_url_with_valid_url() {
    $url = 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js';
    $this->assertTrue(argon_validate_mermaid_cdn_url($url));
}

public function test_validate_cdn_url_with_invalid_url() {
    $url = 'not-a-valid-url';
    $this->assertFalse(argon_validate_mermaid_cdn_url($url));
}

// 测试代码块检测
public function test_has_mermaid_content_with_div_class() {
    $content = '<div class="mermaid">flowchart TD</div>';
    $this->assertTrue(argon_has_mermaid_content($content));
}

public function test_has_mermaid_content_without_mermaid() {
    $content = '<p>Regular paragraph</p>';
    $this->assertFalse(argon_has_mermaid_content($content));
}
```

**JavaScript 单元测试示例**：
```javascript
// 测试主题获取
test('getMermaidTheme returns dark theme in dark mode', () => {
    document.documentElement.classList.add('darkmode');
    expect(getMermaidTheme()).toBe('dark');
});

test('getMermaidTheme returns default theme in light mode', () => {
    document.documentElement.classList.remove('darkmode');
    expect(getMermaidTheme()).toBe('default');
});

// 测试代码块检测
test('isMermaidBlock detects div with mermaid class', () => {
    const div = document.createElement('div');
    div.className = 'mermaid';
    expect(isMermaidBlock(div)).toBe(true);
});

test('isMermaidBlock ignores regular div', () => {
    const div = document.createElement('div');
    expect(isMermaidBlock(div)).toBe(false);
});
```

### 属性测试策略

**测试框架**：使用 fast-check（JavaScript）进行属性测试

**配置要求**：
- 每个属性测试最少运行 100 次迭代
- 每个测试必须引用设计文档中的属性
- 标签格式：`Feature: mermaid-support, Property {number}: {property_text}`

**属性测试示例**：

```javascript
// Feature: mermaid-support, Property 1: 按需加载库
// 对于任意 WordPress 页面，当且仅当页面内容包含 Mermaid 代码块时，主题应该加载 Mermaid JavaScript 库
fc.assert(
    fc.property(
        fc.string(),  // 生成随机页面内容
        fc.boolean(), // 是否包含 Mermaid 代码块
        (content, hasMermaid) => {
            const pageContent = hasMermaid 
                ? content + '<div class="mermaid">flowchart TD</div>'
                : content;
            
            const shouldLoad = argon_has_mermaid_content(pageContent);
            expect(shouldLoad).toBe(hasMermaid);
        }
    ),
    { numRuns: 100 }
);

// Feature: mermaid-support, Property 2: CDN 地址正确性
// 对于任意 CDN 配置选项，生成的脚本 URL 应该与配置选项对应的 CDN 地址匹配
fc.assert(
    fc.property(
        fc.constantFrom('jsdelivr', 'unpkg', 'local'),
        (cdnSource) => {
            const expectedUrls = {
                'jsdelivr': 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js',
                'unpkg': 'https://unpkg.com/mermaid@10/dist/mermaid.min.js',
                'local': '/wp-content/themes/argon/assets/vendor/mermaid/mermaid.min.js'
            };
            
            const actualUrl = argon_get_mermaid_library_url(cdnSource);
            expect(actualUrl).toContain(expectedUrls[cdnSource]);
        }
    ),
    { numRuns: 100 }
);

// Feature: mermaid-support, Property 3: 代码块识别完整性
// 对于任意包含 Mermaid 标记的 HTML 元素，检测器应该能够识别并提取其中的 Mermaid 代码
fc.assert(
    fc.property(
        fc.constantFrom('class', 'language', 'data-lang'),
        fc.string({ minLength: 10 }),
        (markType, code) => {
            let element;
            switch (markType) {
                case 'class':
                    element = document.createElement('div');
                    element.className = 'mermaid';
                    element.textContent = code;
                    break;
                case 'language':
                    element = document.createElement('pre');
                    const codeEl = document.createElement('code');
                    codeEl.className = 'language-mermaid';
                    codeEl.textContent = code;
                    element.appendChild(codeEl);
                    break;
                case 'data-lang':
                    element = document.createElement('pre');
                    element.setAttribute('data-lang', 'mermaid');
                    element.textContent = code;
                    break;
            }
            
            expect(isMermaidBlock(element)).toBe(true);
            expect(extractMermaidCode(element)).toBe(code);
        }
    ),
    { numRuns: 100 }
);

// Feature: mermaid-support, Property 6: 主题模式自动切换
// 对于任意页面主题模式切换，当配置为自动切换时，所有 Mermaid 图表应该重新渲染并使用对应的图表主题
fc.assert(
    fc.property(
        fc.boolean(), // 初始主题模式
        fc.integer({ min: 1, max: 10 }), // 图表数量
        (initialDarkMode, chartCount) => {
            // 设置初始主题
            if (initialDarkMode) {
                document.documentElement.classList.add('darkmode');
            } else {
                document.documentElement.classList.remove('darkmode');
            }
            
            // 创建多个图表
            const charts = [];
            for (let i = 0; i < chartCount; i++) {
                const chart = document.createElement('div');
                chart.className = 'mermaid-rendered';
                chart.dataset.mermaidCode = 'flowchart TD\nA-->B';
                document.body.appendChild(chart);
                charts.push(chart);
            }
            
            // 切换主题
            const newDarkMode = !initialDarkMode;
            if (newDarkMode) {
                document.documentElement.classList.add('darkmode');
            } else {
                document.documentElement.classList.remove('darkmode');
            }
            
            // 触发重新渲染
            reRenderOnThemeSwitch();
            
            // 验证所有图表都使用了新主题
            const expectedTheme = newDarkMode ? 'dark' : 'default';
            charts.forEach(chart => {
                expect(chart.dataset.currentTheme).toBe(expectedTheme);
            });
            
            // 清理
            charts.forEach(chart => chart.remove());
        }
    ),
    { numRuns: 100 }
);

// Feature: mermaid-support, Property 12: CDN 地址验证
// 对于任意用户输入的自定义 CDN 地址，保存前应该验证其格式是否为有效的 URL，并且以 .js 结尾
fc.assert(
    fc.property(
        fc.webUrl(), // 生成随机 URL
        fc.constantFrom('.js', '.css', '.json', ''), // 不同的文件扩展名
        (baseUrl, extension) => {
            const url = baseUrl + extension;
            const isValid = argon_validate_mermaid_cdn_url(url);
            
            // 只有以 .js 结尾的有效 URL 才应该通过验证
            const shouldBeValid = extension === '.js';
            expect(isValid).toBe(shouldBeValid);
        }
    ),
    { numRuns: 100 }
);

// Feature: mermaid-support, Property 15: 批量渲染性能
// 对于任意包含多个 Mermaid 图表的页面，所有图表应该在一次 DOM 遍历中批量收集，然后批量渲染
fc.assert(
    fc.property(
        fc.integer({ min: 1, max: 20 }), // 图表数量
        (chartCount) => {
            // 创建多个图表
            for (let i = 0; i < chartCount; i++) {
                const div = document.createElement('div');
                div.className = 'mermaid';
                div.textContent = `flowchart TD\nA${i}-->B${i}`;
                document.body.appendChild(div);
            }
            
            // 记录 DOM 查询次数
            let queryCount = 0;
            const originalQuerySelectorAll = document.querySelectorAll;
            document.querySelectorAll = function(...args) {
                queryCount++;
                return originalQuerySelectorAll.apply(this, args);
            };
            
            // 执行批量渲染
            renderAllMermaidCharts();
            
            // 恢复原始方法
            document.querySelectorAll = originalQuerySelectorAll;
            
            // 验证只进行了一次 DOM 查询
            expect(queryCount).toBe(1);
            
            // 清理
            document.querySelectorAll('.mermaid').forEach(el => el.remove());
        }
    ),
    { numRuns: 100 }
);
```

### 集成测试

**测试场景**：
1. **完整渲染流程**：从页面加载到图表显示的完整流程
2. **插件兼容性**：与 WP Githuber MD、Markdown Block 等插件的集成
3. **主题切换**：日间/夜间模式切换时的图表重新渲染
4. **错误恢复**：CDN 加载失败时的降级处理

**测试工具**：使用 Playwright 或 Puppeteer 进行端到端测试

### 手动测试清单

由于某些需求难以自动化测试，需要进行手动验证：

- [ ] 图表颜色与页面背景色有足够的对比度（Requirements 4.4）
- [ ] 图表容器样式与主题整体风格一致（Requirements 6.2）
- [ ] 所有 Mermaid 官方图表类型都能正确渲染（Requirements 2.2）
- [ ] 移动端显示效果良好（Requirements 3.2）
- [ ] 错误提示信息友好易懂（Requirements 7.1）
- [ ] 设置页预览功能正常工作（Requirements 5.6）

### 测试覆盖率目标

- **PHP 代码覆盖率**：≥ 80%
- **JavaScript 代码覆盖率**：≥ 85%
- **属性测试覆盖**：所有 18 个正确性属性
- **单元测试覆盖**：所有核心函数和边缘情况

