- 添加多 CDN 备选方案(jsdelivr、unpkg、本地镜像) - 实现递归加载逻辑,主 CDN 失败时自动尝试备用 CDN - 添加 onerror 事件处理,捕获库加载失败 - 所有 CDN 失败时显示友好的错误提示 - 在错误提示中保留原始代码供用户查看 - 添加详细的控制台日志输出 - 创建 PHP 和 HTML 测试文件验证功能 - 暴露 MermaidRenderer 到全局作用域供降级处理使用 Requirements: 1.4, 2.3, 7.1, 7.2, 7.3, 7.4, 7.5
31 KiB
Design Document: Mermaid 图表支持
Overview
本设计文档描述了在 Argon WordPress 主题中集成 Mermaid 图表支持的技术方案。由于 WP-Markdown 编辑器的特殊渲染方式(将 Mermaid 代码块保存为单行,缺少真正的换行符),直接集成 Mermaid 存在技术障碍。
本设计采用插件兼容方案,通过支持主流 Mermaid WordPress 插件(如 WP Githuber MD、Markdown Block 等)来实现功能,同时提供主题级别的样式优化、夜间模式适配和性能优化。
核心设计原则
- 插件优先:依赖成熟的 Mermaid 插件处理代码解析和渲染
- 主题增强:提供样式优化、主题适配和性能优化
- 灵活配置:支持 CDN/本地加载、多种主题、调试模式
- 优雅降级:加载失败时提供备用方案和友好提示
- 性能优先:按需加载、异步加载、缓存优化
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 相关的所有配置选项
接口:
// 获取配置选项
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 库
接口:
// 检测页面是否包含 Mermaid 代码块
function argon_has_mermaid_content($content)
// 加载 Mermaid 库
function argon_enqueue_mermaid_scripts()
// 获取 Mermaid 库 URL
function argon_get_mermaid_library_url()
实现逻辑:
- 在
wp_enqueue_scripts钩子中检查当前页面内容 - 使用正则表达式检测 Mermaid 代码块标记
- 如果检测到,根据配置加载对应的库文件
- 添加 async 或 defer 属性实现异步加载
CDN 地址映射:
$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 配置并启动渲染
接口:
// 初始化 Mermaid 配置
function initMermaidConfig()
// 获取当前主题对应的 Mermaid 主题
function getMermaidTheme()
// 渲染所有 Mermaid 图表
function renderAllMermaidCharts()
// 重新渲染图表(主题切换时)
function reRenderMermaidCharts()
Mermaid 配置对象:
{
startOnLoad: false, // 手动控制渲染时机
theme: 'default', // 根据页面主题动态设置
securityLevel: 'loose', // 允许 HTML 标签
logLevel: 'error', // 生产环境使用 error,调试模式使用 debug
flowchart: {
useMaxWidth: true,
htmlLabels: true
}
}
4. 代码块检测器 (Code Block Detector)
职责:识别页面中的 Mermaid 代码块
接口:
// 检测所有 Mermaid 代码块
function detectMermaidBlocks()
// 检查元素是否为 Mermaid 代码块
function isMermaidBlock(element)
// 提取代码块内容
function extractMermaidCode(element)
检测规则(优先级从高到低):
<div class="mermaid">- 标准格式<pre><code class="language-mermaid">- Markdown 格式<pre data-lang="mermaid">- 自定义属性格式<code class="mermaid">- 简化格式
特殊处理:
- 忽略 HTML 注释中的代码块
- 处理 WP-Markdown 生成的
<script>document.write()</script>格式 - 解码转义字符(
\n,\",\')
5. 样式增强器 (Style Enhancer)
职责:为渲染后的图表添加主题样式
接口:
// 应用容器样式
function applyMermaidContainerStyles(container)
// 应用响应式样式
function applyResponsiveStyles(container)
// 应用夜间模式样式
function applyDarkModeStyles(container, isDarkMode)
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)
职责:处理渲染错误并显示友好提示
接口:
// 处理渲染错误
function handleMermaidError(error, element)
// 显示错误提示
function showErrorMessage(element, errorInfo)
// 记录调试信息
function logDebugInfo(message, data)
错误提示格式:
<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)
职责:监听主题模式切换并重新渲染图表
接口:
// 监听主题切换事件
function listenThemeSwitch()
// 主题切换回调
function onThemeSwitched(isDarkMode)
// 批量重新渲染
function batchReRender(elements)
实现方式:
- 监听 Argon 主题的
argon:theme-switched自定义事件 - 监听
html元素的darkmodeclass 变化(MutationObserver) - 使用防抖避免频繁重新渲染
8. 插件兼容层 (Plugin Compatibility Layer)
职责:检测并兼容主流 Mermaid 插件
接口:
// 检测已安装的 Mermaid 插件
function argon_detect_mermaid_plugins()
// 检查是否已加载 Mermaid 库
function argon_is_mermaid_loaded()
// 避免重复加载
function argon_prevent_duplicate_loading()
支持的插件:
- WP Githuber MD - 检测
wp-githuber-md插件 - Markdown Block - 检测 Gutenberg Mermaid 块
- Code Syntax Block - 检测代码高亮插件的 Mermaid 支持
兼容策略:
- 如果插件已加载 Mermaid 库,主题不再重复加载
- 主题只提供样式增强和主题适配
- 通过
window.mermaid对象检测库是否已加载
Data Models
1. Mermaid 配置对象
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. 代码块元素对象
interface MermaidBlock {
element: HTMLElement; // DOM 元素
code: string; // Mermaid 代码
type: string; // 代码块类型: 'div' | 'pre-code' | 'custom'
rendered: boolean; // 是否已渲染
error: Error | null; // 渲染错误
}
3. 渲染结果对象
interface RenderResult {
success: boolean; // 是否成功
svg: string; // 渲染后的 SVG
error: {
type: string; // 错误类型
message: string; // 错误信息
line: number; // 错误行号
} | null;
}
4. 插件检测结果
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. 错误信息对象
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 库加载失败
处理策略:
- 监听脚本
onerror事件 - 在控制台输出详细错误信息
- 尝试降级到备用 CDN(jsdelivr → unpkg → local)
- 如果所有 CDN 都失败,显示全局提示信息
实现:
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 代码语法错误导致解析失败
处理策略:
- 捕获 Mermaid 渲染异常
- 提取错误类型和行号信息
- 在原代码块位置显示友好的错误提示
- 保留原始代码供用户查看和修正
- 在调试模式下输出详细堆栈信息
错误提示 UI:
<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. 配置验证错误
场景:管理员输入无效的配置选项
处理策略:
- 在保存前验证所有配置项
- CDN URL 格式验证(必须是有效 URL 且以 .js 结尾)
- 主题名称验证(必须是预定义的主题之一)
- 显示具体的验证错误信息
- 阻止保存无效配置
验证函数:
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 库导致冲突
处理策略:
- 在加载前检测
window.mermaid是否已存在 - 如果已存在,跳过库加载,只应用样式增强
- 记录检测结果到控制台
- 在设置页显示插件兼容性状态
检测逻辑:
function checkMermaidLoaded() {
if (typeof window.mermaid !== 'undefined') {
console.log('[Argon Mermaid] 检测到 Mermaid 库已由其他插件加载');
return true;
}
return false;
}
5. 主题切换异常
场景:主题切换时重新渲染失败
处理策略:
- 使用 try-catch 包裹重新渲染逻辑
- 如果重新渲染失败,保留原有图表
- 在控制台输出警告信息
- 不影响页面其他功能
实现:
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 单元测试示例:
// 测试 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 单元测试示例:
// 测试主题获取
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}
属性测试示例:
// 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 }
);
集成测试
测试场景:
- 完整渲染流程:从页面加载到图表显示的完整流程
- 插件兼容性:与 WP Githuber MD、Markdown Block 等插件的集成
- 主题切换:日间/夜间模式切换时的图表重新渲染
- 错误恢复: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 个正确性属性
- 单元测试覆盖:所有核心函数和边缘情况