use super::*;
    use iris_sfc::compile_from_string;
    use crate::animation_engine::{EasingFunction, Keyframe, KeyframesDefinition, AnimationDirection};

    #[test]
    fn test_parse_color_name_simple() {
        // 直接测试颜色名称解析
        let red = crate::css_utils::parse_css_color_name("red");
        assert!(red.is_some());
        
        let blue = crate::css_utils::parse_css_color_name("blue");
        assert!(blue.is_some());
    }


    #[test]
    fn test_parse_hex_color_6digit() {
        // 测试 6 位 hex 颜色
        let color = crate::css_utils::parse_hex_color("#667eea");
        assert!(color.is_some());
        let c = color.unwrap();
        
        assert!((c[0] - 102.0 / 255.0).abs() < 0.01);
        assert!((c[1] - 126.0 / 255.0).abs() < 0.01);
        assert!((c[2] - 234.0 / 255.0).abs() < 0.01);
        assert!((c[3] - 1.0).abs() < 0.01);
    }

    #[test]
    fn test_parse_hex_color_3digit() {
        // 测试 3 位 hex 颜色
        let color = crate::css_utils::parse_hex_color("#f00");
        assert!(color.is_some());
        let c = color.unwrap();
        
        // #f00 = #ff0000 = rgb(255, 0, 0)
        assert!((c[0] - 1.0).abs() < 0.01);
        assert!((c[1] - 0.0).abs() < 0.01);
        assert!((c[2] - 0.0).abs() < 0.01);
    }

    #[test]
    fn test_parse_hex_color_invalid() {
        // 测试无效的 hex 颜色
        assert!(crate::css_utils::parse_hex_color("invalid").is_none());
        assert!(crate::css_utils::parse_hex_color("#zzzzzz").is_none());
        assert!(crate::css_utils::parse_hex_color("#12").is_none());
    }

    #[test]
    fn test_create_orchestrator() {
        let mut orchestrator = RuntimeOrchestrator::new();
        assert!(!orchestrator.is_initialized());
        assert!(orchestrator.js_runtime().eval("1 + 1").is_ok());
    }

    #[test]
    fn test_initialize() {
        let mut orchestrator = RuntimeOrchestrator::new();
        assert!(orchestrator.initialize().is_ok());
        assert!(orchestrator.is_initialized());
        
        // 验证 Vue 环境已注入
        let result = orchestrator.js_runtime().eval("typeof defineComponent");
        assert!(result.is_ok());
    }

    #[test]
    fn test_load_without_initialize() {
        let mut orchestrator = RuntimeOrchestrator::new();
        let result = orchestrator.load_vue_app("test.vue");
        assert!(result.is_err());
    }

    #[test]
    fn test_double_initialize() {
        let mut orchestrator = RuntimeOrchestrator::new();
        assert!(orchestrator.initialize().is_ok());
        
        // 第二次初始化应该返回错误（已经初始化）
        let result = orchestrator.initialize();
        // 允许失败或成功，只要行为一致
        assert!(result.is_err() || result.is_ok());
    }

    #[test]
    fn test_js_execution_before_init() {
        let mut orchestrator = RuntimeOrchestrator::new();
        
        // 未初始化时也可以执行简单 JS（通过 js_runtime 方法）
        let result = orchestrator.js_runtime().eval("'hello'");
        assert!(result.is_ok());
    }

    #[test]
    fn test_load_sfc_with_vtree() {
        use std::fs;
        use std::path::PathBuf;

        // 创建临时测试文件（不使用 script setup，避免模块问题）
        let test_vue = r#"
<template>
  <div class="container">
    <h1>Hello, Iris!</h1>
    <p>This is a test component</p>
  </div>
</template>

<script>
// Simple script without exports
console.log('Component loaded')
</script>

<style scoped>
.container {
  padding: 20px;
}
</style>
"#;

        let temp_path = PathBuf::from("test_phase_b.vue");
        fs::write(&temp_path, test_vue).unwrap();

        let mut orchestrator = RuntimeOrchestrator::new();
        
        // 初始化
        assert!(orchestrator.initialize().is_ok());

        // 加载 SFC 并生成 VTree
        let result = orchestrator.load_sfc_with_vtree(&temp_path);
        assert!(result.is_ok(), "Failed to load SFC with VTree: {:?}", result);

        // 验证 VTree 结构
        let vtree = orchestrator.vtree().expect("VTree should be present");
        match &vtree.root {
            iris_layout::vdom::VNode::Element(elem) => {
                assert_eq!(elem.tag, "div", "Root should be a div");
                assert_eq!(
                    elem.attrs.get("class"),
                    Some(&"container".to_string()),
                    "Root should have class 'container'"
                );
                assert_eq!(elem.children.len(), 2, "Root should have 2 children");
                
                // 验证 h1 子节点
                if let iris_layout::vdom::VNode::Element(h1) = &elem.children[0] {
                    assert_eq!(h1.tag, "h1");
                    assert_eq!(h1.children.len(), 1);
                    if let iris_layout::vdom::VNode::Text(text) = &h1.children[0] {
                        assert_eq!(text, "Hello, Iris!");
                    } else {
                        panic!("h1 child should be a text node");
                    }
                } else {
                    panic!("First child should be an element");
                }
                
                // 验证 p 子节点
                if let iris_layout::vdom::VNode::Element(p) = &elem.children[1] {
                    assert_eq!(p.tag, "p");
                    assert_eq!(p.children.len(), 1);
                    if let iris_layout::vdom::VNode::Text(text) = &p.children[0] {
                        assert_eq!(text, "This is a test component");
                    } else {
                        panic!("p child should be a text node");
                    }
                } else {
                    panic!("Second child should be an element");
                }
            }
            _ => panic!("Root should be an Element node"),
        }

        // 清理临时文件
        fs::remove_file(&temp_path).unwrap();
    }

    #[test]
    fn test_sfc_reactive_render_with_setup() {
        use std::fs;
        use std::path::PathBuf;

        // 创建带响应式绑定的 SFC 测试文件
        let test_vue = r#"
<template>
  <div class="counter">
    <p>Count: {{ count }}</p>
  </div>
</template>

<script>
export default {
  setup() {
    const count = ref(42)
    return { count }
  }
}
</script>
"#;

        let temp_path = PathBuf::from("test_reactive.vue");
        fs::write(&temp_path, test_vue).unwrap();

        let mut orchestrator = RuntimeOrchestrator::new();
        
        // 初始化
        assert!(orchestrator.initialize().is_ok());

        // 加载 SFC 响应式渲染
        let result = orchestrator.load_sfc_with_vtree(&temp_path);
        assert!(result.is_ok(), "Failed to load SFC with VTree: {:?}", result);

        // 验证初始 VTree - setup 返回 count = ref(42)
        let vtree = orchestrator.vtree().expect("VTree should be present");
        match &vtree.root {
            iris_layout::vdom::VNode::Element(elem) => {
                assert_eq!(elem.tag, "div", "Root should be a div");
                assert_eq!(
                    elem.attrs.get("class"),
                    Some(&"counter".to_string()),
                    "Root should have class 'counter'"
                );
                assert_eq!(elem.children.len(), 1, "Root should have 1 child");
                
                // 验证 p 子节点
                if let iris_layout::vdom::VNode::Element(p) = &elem.children[0] {
                    assert_eq!(p.tag, "p");
                    assert_eq!(p.children.len(), 1);
                    if let iris_layout::vdom::VNode::Text(text) = &p.children[0] {
                        // setup 返回 count = ref(42)，渲染后应为 "Count: 42"
                        assert!(
                            text.contains("42"),
                            "Text should contain '42', got: '{}'", text
                        );
                    } else {
                        panic!("p child should be a text node");
                    }
                } else {
                    panic!("First child should be an element");
                }
            }
            _ => panic!("Root should be an Element node"),
        }

        // 验证响应式更新：修改 count 后重新获取 VTree
        let js_result = orchestrator.js_runtime().eval("count = 99");
        assert!(js_result.is_ok(), "Failed to set count: {:?}", js_result);

        // watchEffect 已在数据变化时同步重渲染，直接获取更新后的 VTree
        let update_result = orchestrator.update_vtree_from_reactive();
        assert!(update_result.is_ok(), "Failed to update VTree: {:?}", update_result);

        let updated_vtree = orchestrator.vtree().expect("Updated VTree should be present");
        match &updated_vtree.root {
            iris_layout::vdom::VNode::Element(elem) => {
                if let iris_layout::vdom::VNode::Element(p) = &elem.children[0] {
                    if let iris_layout::vdom::VNode::Text(text) = &p.children[0] {
                        assert!(
                            text.contains("99"),
                            "Text should contain '99' after update, got: '{}'", text
                        );
                        // 验证更新后不再包含旧值
                        assert!(
                            !text.contains("42"),
                            "Text should NOT contain '42' after update, got: '{}'", text
                        );
                    }
                }
            }
            _ => panic!("Root should be an Element node after update"),
        }

        // 清理临时文件
        fs::remove_file(&temp_path).unwrap();
    }

    #[test]
    fn test_sfc_reactive_render_with_diff() {
        use std::fs;
        use std::path::PathBuf;

        // 创建带响应式绑定的 SFC 测试文件
        let test_vue = r#"
<template>
  <div class="counter">
    <p>Count: {{ count }}</p>
    <span>Static text</span>
  </div>
</template>

<script>
export default {
  setup() {
    const count = ref(42)
    const message = ref("Hello")
    return { count, message }
  }
}
</script>
"#;

        let temp_path = PathBuf::from("test_diff_reactive.vue");
        fs::write(&temp_path, test_vue).unwrap();

        let mut orchestrator = RuntimeOrchestrator::new();
        assert!(orchestrator.initialize().is_ok());

        // 加载 SFC 响应式渲染
        let result = orchestrator.load_sfc_with_vtree(&temp_path);
        assert!(result.is_ok(), "Failed to load SFC with VTree: {:?}", result);

        // 计算布局，生成 DOM 树（用于 diff+patches 验证）
        let dom_result = orchestrator.compute_layout();
        assert!(dom_result.is_ok(), "Failed to compute layout: {:?}", dom_result);

        // 初始 VTree 验证
        let vtree = orchestrator.vtree().expect("VTree should be present");
        match &vtree.root {
            iris_layout::vdom::VNode::Element(elem) => {
                assert_eq!(elem.tag, "div");
                assert_eq!(elem.children.len(), 2, "Should have 2 children: p and span");
                
                // 验证 p 标签包含初始 count=42
                if let iris_layout::vdom::VNode::Element(p) = &elem.children[0] {
                    assert_eq!(p.tag, "p");
                    if let iris_layout::vdom::VNode::Text(text) = &p.children[0] {
                        assert!(text.contains("42"), "Initial text should contain 42");
                    }
                }
                
                // 验证 span 标签是静态文本
                if let iris_layout::vdom::VNode::Element(span) = &elem.children[1] {
                    assert_eq!(span.tag, "span");
                    if let iris_layout::vdom::VNode::Text(text) = &span.children[0] {
                        assert_eq!(text, "Static text");
                    }
                }
            }
            _ => panic!("Root should be an Element node"),
        }

        // 初始时 old_vtree 为 None（第一次加载）
        assert!(orchestrator.old_vtree.is_none(), "old_vtree should be None initially");

        // 响应式更新：修改 count
        let js_result = orchestrator.js_runtime().eval("count = 99");
        assert!(js_result.is_ok());

        // 获取响应式更新
        let update_result = orchestrator.update_vtree_from_reactive();
        assert!(update_result.is_ok(), "Failed to update VTree: {:?}", update_result);

        // 验证更新后的 VTree
        let updated_vtree = orchestrator.vtree().expect("Updated VTree should be present");
        match &updated_vtree.root {
            iris_layout::vdom::VNode::Element(elem) => {
                assert_eq!(elem.children.len(), 2);
                
                // p 标签的文本已更新
                if let iris_layout::vdom::VNode::Element(p) = &elem.children[0] {
                    if let iris_layout::vdom::VNode::Text(text) = &p.children[0] {
                        assert!(text.contains("99"), "Updated text should contain 99");
                        assert!(!text.contains("42"), "Updated text should NOT contain 42");
                    }
                }
                
                // span 标签未受影响
                if let iris_layout::vdom::VNode::Element(span) = &elem.children[1] {
                    if let iris_layout::vdom::VNode::Text(text) = &span.children[0] {
                        assert_eq!(text, "Static text", "Static text should remain unchanged");
                    }
                }
            }
            _ => panic!("Root should be an Element node"),
        }

        // old_vtree 现在应该有值（上一次的 VTree）
        assert!(orchestrator.old_vtree.is_some(), "old_vtree should be set after update");

        // 验证 DOM 树仍然有效（没有被全量替换）
        let dom_tree = orchestrator.dom_tree.as_ref().expect("DOM tree should exist");
        match &dom_tree.node_type {
            iris_layout::dom::NodeType::Element(tag) => {
                assert_eq!(tag, "div");
                assert_eq!(dom_tree.children.len(), 2);
            }
            _ => panic!("DOM root should be Element"),
        }

        // 第二次响应式更新：验证多次 diff 也能正常工作
        let js_result = orchestrator.js_runtime().eval("message = 'World'");
        assert!(js_result.is_ok());

        let update_result = orchestrator.update_vtree_from_reactive();
        assert!(update_result.is_ok(), "Failed second update: {:?}", update_result);

        // 验证 old_vtree 仍然有效（应该交换了引用）
        assert!(orchestrator.old_vtree.is_some(), "old_vtree should still be set after second update");

        // 清理临时文件
        fs::remove_file(&temp_path).unwrap();
    }

    #[test]
    fn test_component_registration_and_resolve() {
        use std::fs;
        use std::path::PathBuf;

        // 创建 SFC 测试文件
        let test_vue = r#"
<template>
  <div class="test">
    <p>Component Test</p>
  </div>
</template>

<script>
export default {
  name: "TestComponent",
  setup() {
    const msg = ref("hello")
    return { msg }
  }
}
</script>
"#;

        let temp_path = PathBuf::from("test_component_reg.vue");
        fs::write(&temp_path, test_vue).unwrap();

        let mut orchestrator = RuntimeOrchestrator::new();
        assert!(orchestrator.initialize().is_ok());

        // 加载 SFC
        let result = orchestrator.load_sfc_with_vtree(&temp_path);
        assert!(result.is_ok(), "Failed to load SFC: {:?}", result);

        // 验证组件已注册到 ComponentRegistry
        let check_reg = orchestrator.js_runtime().eval(
            "ComponentRegistry.has('test_component_reg')"
        );
        assert!(check_reg.is_ok(), "Failed to check component registry: {:?}", check_reg);
        assert_eq!(
            check_reg.unwrap().as_boolean(),
            Some(true),
            "Component should be registered in ComponentRegistry"
        );

        // 验证 resolveComponent 可以找到组件
        let resolve_result = orchestrator.js_runtime().eval(
            "typeof resolveComponent('test_component_reg')"
        );
        assert!(resolve_result.is_ok());
        let type_str = resolve_result.unwrap().as_string()
            .map(|s| s.to_std_string_escaped())
            .unwrap_or_default();
        assert_eq!(type_str, "object", "resolveComponent should return component object");

        // 验证 resolveComponent 对未注册组件返回原始名称
        let unknown_result = orchestrator.js_runtime().eval(
            "resolveComponent('UnknownComponent')"
        );
        assert!(unknown_result.is_ok());
        let unknown_val = unknown_result.unwrap().as_string()
            .map(|s| s.to_std_string_escaped())
            .unwrap_or_default();
        assert_eq!(unknown_val, "UnknownComponent", "resolveComponent should return name for unknown components");

        // 清理临时文件
        fs::remove_file(&temp_path).unwrap();
    }

    #[test]
    fn test_hot_reload_end_to_end() {
        use std::fs;
        use std::path::PathBuf;

        // 创建初始 SFC 测试文件
        let initial_vue = r#"
<template>
  <div class="app">
    <h1>Initial Title</h1>
    <p>Initial content</p>
  </div>
</template>

<script>
export default {
  setup() {
    const message = ref("Hello")
    return { message }
  }
}
</script>
"#;

        let temp_path = PathBuf::from("test_hmr_end_to_end.vue");
        fs::write(&temp_path, initial_vue).unwrap();

        let mut orchestrator = RuntimeOrchestrator::new();
        assert!(orchestrator.initialize().is_ok());

        // 1. 初始加载 SFC
        let result = orchestrator.load_sfc_with_vtree(&temp_path);
        assert!(result.is_ok(), "Initial load failed: {:?}", result);

        // 2. 计算布局，生成 DOM 树
        let dom_result = orchestrator.compute_layout();
        assert!(dom_result.is_ok(), "Initial layout failed: {:?}", dom_result);

        // 验证初始 VTree
        let initial_vtree = orchestrator.vtree().expect("VTree should exist");
        match &initial_vtree.root {
            iris_layout::vdom::VNode::Element(elem) => {
                assert_eq!(elem.tag, "div");
                assert_eq!(elem.children.len(), 2);
                if let iris_layout::vdom::VNode::Element(h1) = &elem.children[0] {
                    assert_eq!(h1.tag, "h1");
                    if let iris_layout::vdom::VNode::Text(text) = &h1.children[0] {
                        assert!(text.contains("Initial Title"), "Initial text should be 'Initial Title'");
                    }
                }
            }
            _ => panic!("Root should be Element"),
        }

        // 3. 修改文件内容（模拟用户编辑）
        let updated_vue = r#"
<template>
  <div class="app">
    <h1>Updated Title</h1>
    <p>Updated content after hot reload</p>
  </div>
</template>

<script>
export default {
  setup() {
    const message = ref("World")
    return { message }
  }
}
</script>
"#;
        fs::write(&temp_path, updated_vue).unwrap();

        // 4. 触发热重载
        let project_root = PathBuf::from(".");
        let hot_reload_result = orchestrator.hot_reload(&temp_path, &project_root);
        assert!(hot_reload_result.is_ok(), "Hot reload failed: {:?}", hot_reload_result);

        // 5. 验证 VTree 已更新
        let updated_vtree = orchestrator.vtree().expect("VTree should exist after hot reload");
        match &updated_vtree.root {
            iris_layout::vdom::VNode::Element(elem) => {
                assert_eq!(elem.tag, "div", "Root tag should remain div");
                assert_eq!(elem.children.len(), 2, "Should still have 2 children");

                if let iris_layout::vdom::VNode::Element(h1) = &elem.children[0] {
                    assert_eq!(h1.tag, "h1");
                    if let iris_layout::vdom::VNode::Text(text) = &h1.children[0] {
                        assert!(
                            text.contains("Updated Title"),
                            "H1 text should be 'Updated Title', got: '{}'", text
                        );
                        assert!(
                            !text.contains("Initial Title"),
                            "H1 text should NOT contain 'Initial Title'"
                        );
                    }
                }

                // 验证 p 标签内容也已更新
                if let iris_layout::vdom::VNode::Element(p) = &elem.children[1] {
                    assert_eq!(p.tag, "p");
                    if let iris_layout::vdom::VNode::Text(text) = &p.children[0] {
                        assert!(
                            text.contains("Updated content"),
                            "P text should contain 'Updated content', got: '{}'", text
                        );
                    }
                }
            }
            _ => panic!("Root should be Element after hot reload"),
        }

        // 6. 验证响应式状态保持（如果存在 __VUE_HMR_RUNTIME__）
        let hmr_check = orchestrator.js_runtime().eval(
            "typeof __VUE_HMR_RUNTIME__ !== 'undefined'"
        );
        if let Ok(val) = hmr_check {
            if val.as_boolean() == Some(true) {
                // HMR 运行时存在，验证状态保存机制
                let state_js = r#"(function() {
  __VUE_HMR_RUNTIME__.data['test_hmr_end_to_end'] = { 'saved': true };
  return __VUE_HMR_RUNTIME__.loadState('test_hmr_end_to_end').saved === true;
})()"#.to_string();
                let saved = orchestrator.js_runtime().eval(&state_js);
                assert!(saved.is_ok(), "HMR state save/load failed");
            }
        }

        // 7. 验证标记为需要重新渲染
        assert!(orchestrator.is_dirty(), "Orchestrator should be dirty after hot reload");

        // 8. 清理临时文件
        fs::remove_file(&temp_path).unwrap();
    }

    #[test]
    fn test_vtree_to_dom_conversion() {
        // 这个测试验证 orchestrator 的 build_dom_from_vtree 方法
        // 实际的 VTree → DOM 转换逻辑在 iris-layout 中已测试
        
        use iris_layout::vdom::{VElement, VNode, VTree};
        
        // 手动创建一个 VTree
        let vtree = VTree {
            root: VNode::Element(VElement {
                tag: "div".to_string(),
                attrs: vec![("id".to_string(), "app".to_string())].into_iter().collect(),
                children: vec![
                    VNode::Element(VElement {
                        tag: "h1".to_string(),
                        attrs: Default::default(),
                        children: vec![VNode::Text("Hello".to_string())],
                        key: None,
                    }),
                ],
                key: None,
            }),
        };

        // 转换为 DOM
        let dom_node = vtree.to_dom_node();

        // 验证 DOM 树结构
        assert_eq!(dom_node.tag_name().unwrap(), "div");
        assert_eq!(dom_node.get_attribute("id").unwrap(), "app");
        assert_eq!(dom_node.children.len(), 1);

        // 验证子节点
        let child = &dom_node.children[0];
        assert_eq!(child.tag_name().unwrap(), "h1");
    }

    #[test]
    fn test_load_sfc_without_vtree() {
        let mut orchestrator = RuntimeOrchestrator::new();
        
        // 未初始化时加载应该失败
        let result = orchestrator.load_sfc_with_vtree("test.vue");
        assert!(result.is_err());
    }

    #[test]
    fn test_compute_layout_without_vtree() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        
        // 没有 VTree 时计算布局应该失败
        let result = orchestrator.compute_layout();
        assert!(result.is_err());
    }

    #[test]
    fn test_compute_layout_with_manual_dom() {
        use iris_layout::dom::DOMNode;
        
        // 创建手动 DOM 树
        let mut dom_tree = DOMNode::new_element("div");
        dom_tree.set_attribute("id", "app");
        dom_tree.set_attribute("style", "display: flex; flex-direction: column;");
        
        // 添加子节点
        let mut child1 = DOMNode::new_element("h1");
        child1.set_attribute("style", "color: blue;");
        dom_tree.children.push(child1);
        
        let mut child2 = DOMNode::new_element("p");
        child2.set_attribute("style", "margin: 10px;");
        dom_tree.children.push(child2);

        // 创建编排器并设置 DOM 树
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.dom_tree = Some(dom_tree);
        orchestrator.set_viewport_size(1024.0, 768.0);

        // 计算布局
        let dom_with_layout = orchestrator.dom_tree().unwrap();
        
        // 验证 DOM 树存在
        assert_eq!(dom_with_layout.tag_name().unwrap(), "div");
        assert_eq!(dom_with_layout.children.len(), 2);
    }

    #[test]
    fn test_viewport_size_configuration() {
        let mut orchestrator = RuntimeOrchestrator::new();
        
        // 默认视口
        assert_eq!(orchestrator.viewport_width, 800.0);
        assert_eq!(orchestrator.viewport_height, 600.0);
        
        // 设置新视口
        orchestrator.set_viewport_size(1920.0, 1080.0);
        assert_eq!(orchestrator.viewport_width, 1920.0);
        assert_eq!(orchestrator.viewport_height, 1080.0);
    }

    #[test]
    fn test_generate_render_commands_empty() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        
        // 没有 DOM 树时应该返回空命令列表
        let commands = orchestrator.generate_render_commands();
        assert_eq!(commands.len(), 0);
    }

    #[test]
    fn test_generate_render_commands_with_dom() {
        use iris_layout::dom::DOMNode;
        
        // 创建手动 DOM 树
        let mut dom_tree = DOMNode::new_element("div");
        dom_tree.set_attribute("id", "app");
        
        let mut child = DOMNode::new_element("h1");
        child.set_attribute("style", "color: blue;");
        dom_tree.children.push(child);

        // 创建编排器并设置 DOM 树
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.dom_tree = Some(dom_tree);

        // 生成渲染命令
        let commands = orchestrator.generate_render_commands();
        
        // 当前实现返回空命令（因为没有背景颜色）
        // 这是预期的行为
        let _ = commands.len(); // 验证不 panic 即可
    }

    #[test]
    fn test_dirty_flag_management() {
        let mut orchestrator = RuntimeOrchestrator::new();
        
        // 初始状态应该是 dirty
        assert!(orchestrator.is_dirty());
        
        // 标记为 clean
        orchestrator.dirty = false;
        assert!(!orchestrator.is_dirty());
        
        // 再次标记为 dirty
        orchestrator.mark_dirty();
        assert!(orchestrator.is_dirty());
    }

    #[test]
    fn test_target_fps_configuration() {
        let mut orchestrator = RuntimeOrchestrator::new();
        
        // 默认 60 FPS
        assert_eq!(orchestrator.target_fps(), 60);
        
        // 设置新帧率
        orchestrator.set_target_fps(120);
        assert_eq!(orchestrator.target_fps(), 120);
        
        // 边界测试：最小值
        orchestrator.set_target_fps(0);
        assert_eq!(orchestrator.target_fps(), 1);
        
        // 边界测试：最大值
        orchestrator.set_target_fps(200);
        assert_eq!(orchestrator.target_fps(), 144);
    }

    #[test]
    fn test_render_frame_dirty_check() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        
        // 设置非常高的 FPS 以避免帧率限制影响测试
        orchestrator.set_target_fps(10000);
        
        // 初始是 dirty，应该渲染
        let first_render = orchestrator.render_frame();
        assert!(first_render);
        
        // 渲染后变为 clean
        assert!(!orchestrator.is_dirty());
        
        // 再次渲染应该返回 false（因为没有标记 dirty）
        let second_render = orchestrator.render_frame();
        assert!(!second_render);
        
        // 标记 dirty 后再渲染
        orchestrator.mark_dirty();
        
        // 重置时间戳以绕过帧率限制
        orchestrator.last_frame_time = None;
        
        let third_render = orchestrator.render_frame();
        assert!(third_render);
    }

    #[test]
    fn test_current_fps_tracking() {
        let mut orchestrator = RuntimeOrchestrator::new();
        
        // 初始帧率应该是 0
        assert_eq!(orchestrator.current_fps(), 0.0);
        
        // 渲染几帧后应该有帧率数据
        orchestrator.mark_dirty();
        orchestrator.render_frame();
        
        // 帧率应该大于 0
        assert!(orchestrator.current_fps() >= 0.0);
    }

    #[test]
    fn test_event_listener_management() {
        use std::cell::RefCell;
        use std::rc::Rc;
        
        let mut orchestrator = RuntimeOrchestrator::new();
        
        // 初始没有监听器
        assert_eq!(orchestrator.event_listener_count(), 0);
        
        // 添加监听器
        let clicked = Rc::new(RefCell::new(false));
        let clicked_clone = clicked.clone();
        
        orchestrator.add_event_listener(
            1,
            EventType::Click,
            Box::new(move |_event| {
                *clicked_clone.borrow_mut() = true;
            }),
            false,
        );
        
        assert_eq!(orchestrator.event_listener_count(), 1);
        
        // 触发事件（通过 queue_event + render_frame 异步处理）
        let event = Event::new(EventType::Click, 1);
        orchestrator.handle_event(event);
        orchestrator.render_frame();
        
        assert!(*clicked.borrow());
        
        // 移除监听器
        orchestrator.remove_event_listener(1, EventType::Click);
        assert_eq!(orchestrator.event_listener_count(), 0);
    }

    #[test]
    fn test_mouse_click_handling() {
        use std::cell::RefCell;
        use std::rc::Rc;
        use iris_dom::event::EventData;
        
        let mut orchestrator = RuntimeOrchestrator::new();
        
        // 添加点击监听器
        let click_data = Rc::new(RefCell::new(None));
        let click_data_clone = click_data.clone();
        
        orchestrator.add_event_listener(
            1,
            EventType::Click,
            Box::new(move |event| {
                if let EventData::Mouse(mouse_data) = &event.data {
                    *click_data_clone.borrow_mut() = Some((mouse_data.x, mouse_data.y));
                }
            }),
            false,
        );
        
        // 处理鼠标点击（异步处理，需要 render_frame 触发）
        orchestrator.handle_mouse_click(1, 100.0, 200.0, 0);
        orchestrator.render_frame();
        
        // 验证事件数据
        let data = click_data.borrow();
        assert!(data.is_some());
        let (x, y) = data.unwrap();
        assert_eq!(x, 100.0);
        assert_eq!(y, 200.0);
    }

    #[test]
    fn test_keyboard_event_handling() {
        use std::cell::RefCell;
        use std::rc::Rc;
        use iris_dom::event::EventData;
        
        let mut orchestrator = RuntimeOrchestrator::new();
        
        // 添加键盘监听器
        let key_pressed = Rc::new(RefCell::new(String::new()));
        let key_pressed_clone = key_pressed.clone();
        
        orchestrator.add_event_listener(
            1,
            EventType::KeyDown,
            Box::new(move |event| {
                if let EventData::Keyboard(key_data) = &event.data {
                    *key_pressed_clone.borrow_mut() = key_data.key.clone();
                }
            }),
            false,
        );
        
        // 处理键盘事件（异步处理，需要 render_frame 触发）
        orchestrator.handle_keyboard_event(1, "Enter".to_string(), 13, false, false, false);
        orchestrator.render_frame();
        
        // 验证按键数据
        assert_eq!(*key_pressed.borrow(), "Enter");
    }

    /// 测试键盘修饰符: 验证 key_code 正确传递到监听器
    #[test]
    fn test_keyboard_modifier_key_code() {
        use std::cell::RefCell;
        use std::rc::Rc;
        use iris_dom::event::EventData;

        let mut orchestrator = RuntimeOrchestrator::new();

        let last_key_code = Rc::new(RefCell::new(0u32));
        let last_key_code_clone = last_key_code.clone();

        orchestrator.add_event_listener(
            1,
            EventType::KeyDown,
            Box::new(move |event| {
                if let EventData::Keyboard(key_data) = &event.data {
                    *last_key_code_clone.borrow_mut() = key_data.key_code;
                }
            }),
            false,
        );

        // Enter 键
        orchestrator.handle_keyboard_event(1, "Enter".to_string(), 13, false, false, false);
        orchestrator.render_frame();
        assert_eq!(*last_key_code.borrow(), 13, "KeyCode should be 13 (Enter)");

        // ESC 键
        orchestrator.handle_keyboard_event(1, "Escape".to_string(), 27, false, false, false);
        orchestrator.render_frame();
        assert_eq!(*last_key_code.borrow(), 27, "KeyCode should be 27 (Escape)");

        // Tab 键
        orchestrator.handle_keyboard_event(1, "Tab".to_string(), 9, false, false, false);
        orchestrator.render_frame();
        assert_eq!(*last_key_code.borrow(), 9, "KeyCode should be 9 (Tab)");
    }

    #[test]
    fn test_clear_event_listeners() {
        let mut orchestrator = RuntimeOrchestrator::new();
        
        // 添加多个监听器
        orchestrator.add_event_listener(1, EventType::Click, Box::new(|_| {}), false);
        orchestrator.add_event_listener(2, EventType::Click, Box::new(|_| {}), false);
        orchestrator.add_event_listener(1, EventType::KeyDown, Box::new(|_| {}), false);
        
        assert_eq!(orchestrator.event_listener_count(), 3);
        
        // 清除所有监听器
        orchestrator.clear_event_listeners();
        assert_eq!(orchestrator.event_listener_count(), 0);
    }

    #[test]
    fn test_sfc_compilation() {
        let vue_source = r#"
            <template>
                <div>Test</div>
            </template>
            <script>
                export default { name: 'Test' }
            </script>
        "#;
        
        let result = compile_from_string("TestComponent", vue_source);
        assert!(result.is_ok());
        
        let module = result.unwrap();
        assert_eq!(module.name, "TestComponent");
        assert!(!module.script.is_empty());
    }

    #[test]
    fn test_runtime_lifecycle() {
        let mut orchestrator = RuntimeOrchestrator::new();
        
        // 1. 创建后未初始化
        assert!(!orchestrator.is_initialized());
        
        // 2. 初始化成功
        assert!(orchestrator.initialize().is_ok());
        assert!(orchestrator.is_initialized());
        
        // 3. 可以执行 JS
        let result = orchestrator.js_runtime().eval("true");
        assert!(result.is_ok());
    }

    #[test]
    fn test_bom_injection_after_init() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        
        // 验证 BOM API 已注入
        let result = orchestrator.js_runtime().eval("typeof window");
        assert!(result.is_ok());
    }

    #[test]
    fn test_compile_and_load_simple() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        
        // 创建一个简单的 Vue 文件
        let vue_source = r#"
            <template>
                <div>Hello World</div>
            </template>
            <script>
                export default {
                    name: 'SimpleApp'
                }
            </script>
        "#;
        
        // 编译应该成功（但执行会失败，因为 Boa 不支持 export）
        let compiled = compile_from_string("SimpleApp", vue_source);
        assert!(compiled.is_ok());
    }

    #[test]
    fn test_js_error_handling() {
        let mut orchestrator = RuntimeOrchestrator::new();
        
        // 测试语法错误处理
        let result = orchestrator.js_runtime().eval("if (true) {");
        assert!(result.is_err());
    }

    // ==========================================
    // 动画引擎集成测试
    // ==========================================

    #[test]
    fn test_animation_fields_initialized() {
        let orchestrator = RuntimeOrchestrator::new();
        
        // 验证动画相关字段已正确初始化
        assert!(orchestrator.element_animations.is_empty(), "element_animations should be empty");
        assert!(orchestrator.keyframe_animations.is_empty(), "keyframe_animations should be empty");
        assert!(orchestrator.animated_values_cache.is_empty(), "animated_values_cache should be empty");
        assert!(!orchestrator.has_active_animations(), "no animations initially");
        assert_eq!(orchestrator.get_animated_value(1, "opacity"), None, "no value for unanimated element");
    }

    #[test]
    fn test_start_transition_basic() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        
        let config = TransitionConfig {
            property: "opacity".to_string(),
            duration: 50000.0,
            easing: EasingFunction::Linear,
            delay: 0.0,
        };
        
        orchestrator.start_transition(1, "opacity", 0.0, 1.0, &config);
        
        // 验证动画状态已创建
        assert!(orchestrator.element_animations.contains_key(&1), "element 1 should have animation state");
        assert!(orchestrator.has_active_animations(), "should report active animations");
        assert!(orchestrator.dirty, "start_transition should mark dirty");
        
        // 验证 transition 配置已存储
        let state = orchestrator.element_animations.get(&1).unwrap();
        assert_eq!(state.active_transitions.len(), 1, "should have 1 active transition");
        assert!(state.active_transitions.contains_key("opacity"), "should track opacity transition");
    }

    #[test]
    fn test_has_active_animations_detection() {
        let mut orchestrator = RuntimeOrchestrator::new();
        
        // 初始无动画
        assert!(!orchestrator.has_active_animations());
        
        let config = TransitionConfig {
            property: "opacity".to_string(),
            duration: 50000.0,
            easing: EasingFunction::Linear,
            delay: 0.0,
        };
        
        orchestrator.start_transition(1, "opacity", 0.0, 1.0, &config);
        assert!(orchestrator.has_active_animations());
        
        // 清除后应不再有活动动画
        orchestrator.clear_animations();
        assert!(!orchestrator.has_active_animations());
    }

    #[test]
    fn test_start_keyframe_animation_basic() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        
        // 创建关键帧定义
        let mut definition = KeyframesDefinition::new("fadeIn");
        definition.add_keyframe(Keyframe::new(0.0).with_property("opacity", 0.0));
        definition.add_keyframe(Keyframe::new(1.0).with_property("opacity", 1.0));
        
        let anim = KeyframeAnimation::new(
            1,
            &definition,
            1000.0,
            Some(1),
            AnimationDirection::Normal,
            FillMode::Forwards,
            0.0,
        );
        
        orchestrator.start_keyframe_animation(anim);
        
        // 验证关键帧动画已存储
        assert_eq!(orchestrator.keyframe_animations.len(), 1, "should have 1 keyframe animation");
        assert!(orchestrator.has_active_animations(), "should report active animations");
        assert!(orchestrator.dirty, "should mark dirty");
        
        // 验证动画属性
        let stored = &orchestrator.keyframe_animations[0];
        assert_eq!(stored.animation_name, "fadeIn");
        assert!(!stored.completed, "should not be completed yet");
        assert!(!stored.paused, "should not be paused");
    }

    #[test]
    fn test_clear_animations_resets_all() {
        let mut orchestrator = RuntimeOrchestrator::new();
        
        // 添加一个过渡动画
        let config = TransitionConfig {
            property: "opacity".to_string(),
            duration: 50000.0,
            easing: EasingFunction::Linear,
            delay: 0.0,
        };
        orchestrator.start_transition(1, "opacity", 0.0, 1.0, &config);
        
        // 添加一个关键帧动画
        let mut definition = KeyframesDefinition::new("test");
        definition.add_keyframe(Keyframe::new(0.0).with_property("opacity", 0.0));
        definition.add_keyframe(Keyframe::new(1.0).with_property("opacity", 1.0));
        let anim = KeyframeAnimation::new(
            2, &definition, 1000.0, Some(1),
            AnimationDirection::Normal, FillMode::Forwards, 0.0,
        );
        orchestrator.start_keyframe_animation(anim);
        
        assert!(orchestrator.has_active_animations());
        assert_eq!(orchestrator.element_animations.len(), 1);
        assert_eq!(orchestrator.keyframe_animations.len(), 1);
        
        // 清除全部
        orchestrator.clear_animations();
        
        assert!(orchestrator.element_animations.is_empty(), "element_animations should be empty after clear");
        assert!(orchestrator.keyframe_animations.is_empty(), "keyframe_animations should be empty after clear");
        assert!(orchestrator.animated_values_cache.is_empty(), "animated_values_cache should be empty after clear");
        assert!(!orchestrator.has_active_animations(), "no active animations after clear");
    }

    #[test]
    fn test_animation_keeps_dirty_in_render_loop() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        orchestrator.set_target_fps(10000);
        
        // 启动一个长时间的过渡动画
        let config = TransitionConfig {
            property: "opacity".to_string(),
            duration: 50000.0, // 50秒，足够长
            easing: EasingFunction::Linear,
            delay: 0.0,
        };
        orchestrator.start_transition(1, "opacity", 0.0, 1.0, &config);
        
        // 第一次渲染 - 动画应保持 dirty
        orchestrator.last_frame_time = None;
        let rendered = orchestrator.render_frame();
        assert!(rendered, "should render frame");
        assert!(orchestrator.dirty, "dirty should stay true when animation is active");
        
        // 第二次渲染 - 仍应保持 dirty
        orchestrator.last_frame_time = None;
        let rendered2 = orchestrator.render_frame();
        assert!(rendered2, "should render second frame");
        assert!(orchestrator.dirty, "dirty should still be true for ongoing animation");
    }

    #[test]
    fn test_animation_completion_clears_dirty() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        orchestrator.set_target_fps(10000);
        
        // 启动一个零持续时间的动画（立即完成）
        let config = TransitionConfig {
            property: "opacity".to_string(),
            duration: 0.0, // 瞬时完成
            easing: EasingFunction::Linear,
            delay: 0.0,
        };
        orchestrator.start_transition(1, "opacity", 0.0, 1.0, &config);
        
        // 渲染 - 动画应立即完成
        orchestrator.last_frame_time = None;
        let rendered = orchestrator.render_frame();
        assert!(rendered);
        
        // 动画应已结束，dirty 应被清除
        assert!(!orchestrator.has_active_animations(), "instant animation should complete");
        assert!(!orchestrator.dirty, "dirty should be false when no animations active");
    }

    #[test]
    fn test_pause_and_resume_keyframe() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        
        let mut definition = KeyframesDefinition::new("test");
        definition.add_keyframe(Keyframe::new(0.0).with_property("opacity", 0.0));
        definition.add_keyframe(Keyframe::new(1.0).with_property("opacity", 1.0));
        
        let anim = KeyframeAnimation::new(
            1, &definition, 100000.0, Some(1),
            AnimationDirection::Normal, FillMode::Forwards, 0.0,
        );
        orchestrator.start_keyframe_animation(anim);
        assert_eq!(orchestrator.keyframe_animations.len(), 1);
        assert!(!orchestrator.keyframe_animations[0].paused);
        
        // 暂停
        orchestrator.pause_element_animations(1);
        assert!(orchestrator.keyframe_animations[0].paused, "should be paused");
        
        // 恢复
        orchestrator.resume_element_animations(1);
        assert!(!orchestrator.keyframe_animations[0].paused, "should be resumed");
    }

    #[test]
    fn test_reset_element_animations() {
        let mut orchestrator = RuntimeOrchestrator::new();
        
        let config = TransitionConfig {
            property: "opacity".to_string(),
            duration: 50000.0,
            easing: EasingFunction::Linear,
            delay: 0.0,
        };
        
        orchestrator.start_transition(1, "opacity", 0.0, 1.0, &config);
        orchestrator.start_transition(2, "opacity", 1.0, 0.0, &config);
        assert_eq!(orchestrator.element_animations.len(), 2, "should have 2 animated elements");
        
        // 仅重置元素 1
        orchestrator.reset_element_animations(1);
        assert!(!orchestrator.element_animations.contains_key(&1), "element 1 removed");
        assert!(orchestrator.element_animations.contains_key(&2), "element 2 should still exist");
        
        // 重置不存在的元素（不应 panic）
        orchestrator.reset_element_animations(999);
    }

    #[test]
    fn test_apply_animated_values_to_dom() {
        use iris_layout::dom::DOMNode;
        
        let mut orchestrator = RuntimeOrchestrator::new();
        
        // 创建 DOM 树
        let mut root = DOMNode::new_element("div");
        root.set_attribute("id", "root");
        
        let mut child = DOMNode::new_element("p");
        child.set_attribute("style", "color: red; font-size: 14px;");
        root.children.push(child);
        orchestrator.dom_tree = Some(root);
        
        // 手动填充动画值缓存
        // element 1 = div (DFS), element 2 = p
        let mut div_values = HashMap::new();
        div_values.insert("opacity".to_string(), 0.5f32);
        orchestrator.animated_values_cache.insert(1, div_values);
        
        let mut p_values = HashMap::new();
        p_values.insert("font-size".to_string(), 20.0f32);
        orchestrator.animated_values_cache.insert(2, p_values);
        
        // 应用动画值到 DOM
        orchestrator.apply_animated_values_to_dom();
        
        // 验证 DOM 元素样式已更新
        let dom_ref = orchestrator.dom_tree.as_ref().unwrap();
        
        let div_style = dom_ref.get_attribute("style").unwrap();
        assert!(div_style.contains("opacity: 0.5"), "div should have opacity: 0.5, got: {}", div_style);
        
        let p_style = dom_ref.children[0].get_attribute("style").unwrap();
        assert!(p_style.contains("color: red"), "p should keep original color, got: {}", p_style);
        assert!(p_style.contains("font-size: 20"), "p should have font-size: 20, got: {}", p_style);
    }

    #[test]
    fn test_get_animated_value_after_update() {
        let mut orchestrator = RuntimeOrchestrator::new();
        
        // 初始无动画值
        assert_eq!(orchestrator.get_animated_value(1, "opacity"), None);
        
        // 启动过渡动画
        let config = TransitionConfig {
            property: "opacity".to_string(),
            duration: 50000.0,
            easing: EasingFunction::Linear,
            delay: 0.0,
        };
        orchestrator.start_transition(1, "opacity", 0.5, 1.0, &config);
        
        // 更新动画状态
        orchestrator.update_animations();
        
        // 应能获取到动画值（在 0.5~1.0 之间）
        let value = orchestrator.get_animated_value(1, "opacity");
        assert!(value.is_some(), "should retrieve animated value after update");
        if let Some(v) = value {
            assert!(v >= 0.5 && v <= 1.0, "opacity should be between 0.5 and 1.0, got {}", v);
        }
        
        // 不存在的属性应返回 None
        assert_eq!(orchestrator.get_animated_value(1, "transform"), None);
        // 不存在的元素应返回 None
        assert_eq!(orchestrator.get_animated_value(999, "opacity"), None);
    }

    #[test]
    fn test_multiple_element_animations_independent() {
        let mut orchestrator = RuntimeOrchestrator::new();
        
        let config_opacity = TransitionConfig {
            property: "opacity".to_string(),
            duration: 50000.0,
            easing: EasingFunction::Linear,
            delay: 0.0,
        };
        
        let config_width = TransitionConfig {
            property: "width".to_string(),
            duration: 30000.0,
            easing: EasingFunction::EaseInOut,
            delay: 100.0,
        };
        
        // 元素 1：opacity 和 width 两个动画
        orchestrator.start_transition(1, "opacity", 0.0, 1.0, &config_opacity);
        orchestrator.start_transition(1, "width", 100.0, 200.0, &config_width);
        // 元素 2：单个 opacity 动画
        orchestrator.start_transition(2, "opacity", 1.0, 0.0, &config_opacity);
        
        assert_eq!(orchestrator.element_animations.len(), 2, "should have 2 animated elements");
        assert!(orchestrator.has_active_animations());
        
        // 元素 1 应有 2 个活动过渡
        let state1 = orchestrator.element_animations.get(&1).unwrap();
        assert_eq!(state1.active_transitions.len(), 2, "element 1 should have 2 transitions");
        assert!(state1.active_transitions.contains_key("opacity"));
        assert!(state1.active_transitions.contains_key("width"));
        
        // 元素 2 应有 1 个活动过渡
        let state2 = orchestrator.element_animations.get(&2).unwrap();
        assert_eq!(state2.active_transitions.len(), 1, "element 2 should have 1 transition");
        
        // 清除元素 1 后，元素 2 应仍存在
        orchestrator.reset_element_animations(1);
        assert!(!orchestrator.element_animations.contains_key(&1), "element 1 removed");
        assert!(orchestrator.element_animations.contains_key(&2), "element 2 should remain");
    }

    #[test]
    fn test_keyframe_animation_update_progress() {
        let mut orchestrator = RuntimeOrchestrator::new();
        
        let mut definition = KeyframesDefinition::new("fadeOut");
        definition.add_keyframe(Keyframe::new(0.0).with_property("opacity", 1.0));
        definition.add_keyframe(Keyframe::new(1.0).with_property("opacity", 0.0));
        
        let anim = KeyframeAnimation::new(
            1, &definition, 10.0, Some(1),
            AnimationDirection::Normal, FillMode::Forwards, 0.0,
        );
        orchestrator.start_keyframe_animation(anim);
        
        assert!(orchestrator.has_active_animations());
        assert!(!orchestrator.keyframe_animations[0].completed);
        
        // 以 15ms 为间隔前进多次，确保超过 10ms 持续时间
        for _ in 0..8 {
            std::thread::sleep(std::time::Duration::from_millis(15));
            orchestrator.update_animations();
            if orchestrator.keyframe_animations[0].completed {
                break;
            }
        }
        
        assert!(
            orchestrator.keyframe_animations[0].completed,
            "keyframe should be completed after enough time (elapsed: {:.0}ms)",
            orchestrator.keyframe_animations[0].elapsed_time,
        );
    }

    #[test]
    fn test_dirty_rect_manager_initialized() {
        let orchestrator = RuntimeOrchestrator::new();
        
        // 验证脏矩形管理器已初始化
        let stats = orchestrator.dirty_rect_manager.get_stats();
        assert_eq!(stats.total_dirty_rects, 0, "no dirty rects initially");
        assert!(!stats.needs_full_redraw, "no full redraw initially");
        assert!(orchestrator.dirty_rect_manager.is_enabled(), "dirty rect optimization enabled by default");
    }

    #[test]
    fn test_mark_area_dirty() {
        let mut orchestrator = RuntimeOrchestrator::new();
        
        // 标记特定区域为脏
        orchestrator.mark_area_dirty(100.0, 100.0, 50.0, 50.0);
        
        assert!(orchestrator.dirty, "mark_area_dirty should set dirty flag");
        
        // 验证脏矩形已记录（计算重绘区域后应有脏矩形信息）
        let regions = orchestrator.dirty_rect_manager.compute_redraw_regions();
        assert!(!regions.is_empty(), "should have redraw regions after marking area dirty");
    }

    #[test]
    fn test_mark_full_dirty() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.dirty = false;
        
        orchestrator.mark_full_dirty();
        
        assert!(orchestrator.dirty, "mark_full_dirty should set dirty flag");
        
        // 验证全屏标记为脏
        let regions = orchestrator.dirty_rect_manager.compute_redraw_regions();
        assert_eq!(regions.len(), 1, "full dirty should produce 1 region");
        assert!((regions[0].width - 800.0).abs() < f32::EPSILON, "full width should be 800");
        assert!((regions[0].height - 600.0).abs() < f32::EPSILON, "full height should be 600");
    }

    #[test]
    fn test_set_viewport_size_syncs_dirty_rect() {
        let mut orchestrator = RuntimeOrchestrator::new();
        
        // 修改视口尺寸
        orchestrator.set_viewport_size(1920.0, 1080.0);
        
        // 验证视口已更新
        assert_eq!(orchestrator.viewport_width, 1920.0);
        assert_eq!(orchestrator.viewport_height, 1080.0);
        
        // 验证脏矩形管理器已同步新尺寸
        let regions = orchestrator.dirty_rect_manager.compute_redraw_regions();
        assert!((regions[0].width - 1920.0).abs() < f32::EPSILON, "dirty rect width should match viewport");
        assert!((regions[0].height - 1080.0).abs() < f32::EPSILON, "dirty rect height should match viewport");
    }

    #[test]
    fn test_dirty_rect_stats_api() {
        let mut orchestrator = RuntimeOrchestrator::new();
        
        // 初始统计信息
        let stats = orchestrator.dirty_rect_stats();
        assert_eq!(stats.total_dirty_rects, 0);
        
        // 标记区域后统计信息应有变化
        orchestrator.mark_area_dirty(0.0, 0.0, 100.0, 100.0);
        orchestrator.mark_area_dirty(50.0, 50.0, 200.0, 200.0);
        
        let _regions = orchestrator.dirty_rect_manager.compute_redraw_regions();
        let stats = orchestrator.dirty_rect_stats();
        assert!(stats.total_dirty_rects >= 2, "should have tracked 2+ dirty rects");
    }

    #[test]
    fn test_dirty_rect_cleared_after_render_frame() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        orchestrator.set_target_fps(10000);
        
        // 设置 DOM 树使渲染有内容
        use iris_layout::dom::DOMNode;
        let root = DOMNode::new_element("div");
        orchestrator.dom_tree = Some(root);
        
        // 标记脏区域
        orchestrator.mark_area_dirty(10.0, 10.0, 100.0, 100.0);
        
        // 渲染一帧
        orchestrator.last_frame_time = None;
        orchestrator.dirty = true;
        let rendered = orchestrator.render_frame();
        assert!(rendered, "should render frame");
        
        // 渲染完成后脏矩形应被清除
        let _stats = orchestrator.dirty_rect_manager.get_stats();
        // compute_redraw_regions 已被 render_frame 调用，脏区域已处理
        // 验证没有新的脏矩形（已清空）
        assert_eq!(orchestrator.dirty_rect_manager.dirty_count(), 0, "dirty rects should be cleared after render");
    }

    #[test]
    fn test_set_dirty_rect_optimization() {
        let mut orchestrator = RuntimeOrchestrator::new();
        
        // 默认启用
        assert!(orchestrator.dirty_rect_manager.is_enabled());
        
        // 禁用
        orchestrator.set_dirty_rect_optimization(false);
        assert!(!orchestrator.dirty_rect_manager.is_enabled());
        
        // 重新启用
        orchestrator.set_dirty_rect_optimization(true);
        assert!(orchestrator.dirty_rect_manager.is_enabled());
    }

    #[test]
    fn test_render_frame_fps_limit() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        
        // 设置极低 FPS（1 fps），确保帧率限制生效
        orchestrator.set_target_fps(1);
        orchestrator.dirty = true;
        
        // 第一次渲染 - 应该成功
        orchestrator.last_frame_time = None;
        assert!(orchestrator.render_frame(), "first render should succeed");
        
        // 立即第二次渲染 - 应被 FPS 限制阻止
        let second = orchestrator.render_frame();
        assert!(!second, "second immediate render should be blocked by FPS limit");
        
        // 即使标记 dirty 也不应该渲染（FPS 限制优先）
        orchestrator.dirty = true;
        let third = orchestrator.render_frame();
        assert!(!third, "render should still be FPS-limited even when dirty");
        
        // FPS 阻止后 dirty 应保持不变
        assert!(orchestrator.is_dirty(), "dirty should remain true when FPS blocks rendering");
    }

    #[test]
    fn test_render_frame_returns_false_when_clean() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        orchestrator.set_target_fps(10000);
        
        // 第一次渲染（初始 dirty）
        orchestrator.last_frame_time = None;
        assert!(orchestrator.render_frame(), "first render should succeed");
        
        // 渲染后 dirty=false，再次调用应返回 false
        let second = orchestrator.render_frame();
        assert!(!second, "render should return false when not dirty");
        
        // 主动标记 dirty 后可再次渲染
        orchestrator.dirty = true;
        orchestrator.last_frame_time = None;
        assert!(orchestrator.render_frame(), "render should succeed after mark_dirty");
    }

    #[test]
    fn test_render_frame_no_dom_tree() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        orchestrator.set_target_fps(10000);
        
        // 没有 DOM 树时渲染（generate_render_commands 返回空列表）
        // 不应 panic，应正常返回 true
        orchestrator.last_frame_time = None;
        orchestrator.dirty = true;
        let result = orchestrator.render_frame();
        assert!(result, "render_frame should return true even without DOM tree");
        
        // dirty 标志应被清除
        assert!(!orchestrator.is_dirty(), "dirty should be cleared after render");
    }

    #[test]
    fn test_render_frame_gpu_wrapper_no_renderer() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        orchestrator.set_target_fps(10000);
        
        // 没有 GPU 渲染器时 render_frame_gpu 应返回 false
        orchestrator.dirty = true;
        orchestrator.last_frame_time = None;
        let result = orchestrator.render_frame_gpu();
        assert!(!result, "render_frame_gpu should return false without GPU renderer");
        
        // 验证 has_gpu_renderer 返回 false
        assert!(!orchestrator.has_gpu_renderer(), "no GPU renderer should be set");
    }

    #[test]
    fn test_render_frame_gpu_wrapper_does_not_consume_dirty() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        orchestrator.set_target_fps(10000);
        
        // render_frame_gpu 返回 false 后，dirty 状态应保持不变
        orchestrator.dirty = true;
        orchestrator.last_frame_time = None;
        let result = orchestrator.render_frame_gpu();
        assert!(!result, "should return false without GPU");
        
        // dirty 不应被清除（因为 render_frame 没有被调用）
        assert!(orchestrator.is_dirty(), "dirty should remain unchanged when render_frame_gpu returns early");
        
        // 现在用 render_frame 正常渲染
        orchestrator.last_frame_time = None;
        let result = orchestrator.render_frame();
        assert!(result, "render_frame should succeed");
    }

    #[test]
    fn test_render_frame_consecutive_full_frames() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        orchestrator.set_target_fps(10000);
        
        // 连续多次渲染循环
        for i in 0..5 {
            orchestrator.dirty = true;
            orchestrator.last_frame_time = None;
            let result = orchestrator.render_frame();
            assert!(result, "frame {} should render successfully", i);
            
            // 每次渲染后 dirty 应被清除（没有动画时）
            assert!(!orchestrator.is_dirty(), "dirty should be cleared after frame {}", i);
        }
    }

    #[test]
    fn test_render_frame_with_keyframe_and_transition_cleanup() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        orchestrator.set_target_fps(10000);
        
        // 启动一个过渡动画和一个关键帧动画（使用极短而非零持续时间，避免 NaN 运算）
        let config = TransitionConfig {
            property: "opacity".to_string(),
            duration: 0.001, // 1 微秒，近乎瞬时
            easing: EasingFunction::Linear,
            delay: 0.0,
        };
        orchestrator.start_transition(1, "opacity", 0.0, 1.0, &config);
        
        let mut definition = KeyframesDefinition::new("instant");
        definition.add_keyframe(Keyframe::new(0.0).with_property("opacity", 1.0));
        definition.add_keyframe(Keyframe::new(1.0).with_property("opacity", 0.0));
        let anim = KeyframeAnimation::new(
            2, &definition, 0.001, Some(1),
            AnimationDirection::Normal, FillMode::None, 0.0,
        );
        orchestrator.start_keyframe_animation(anim);
        
        // 第一帧：更新动画状态（极短动画会在此更新 current_iteration）
        orchestrator.last_frame_time = None;
        orchestrator.dirty = true;
        let result = orchestrator.render_frame();
        assert!(result, "first render should succeed");
        
        // 由于关键帧动画的 current_iteration 更新发生在迭代检查之后,
        // 需要第二帧才能完成并清除动画
        orchestrator.last_frame_time = None;
        orchestrator.dirty = true;
        let result = orchestrator.render_frame();
        assert!(result, "second render should succeed");
        
        // 动画应全部完成，dirty 应被清除
        assert!(!orchestrator.has_active_animations(), "instant animations should complete after two frames");
        assert!(!orchestrator.is_dirty(), "dirty should be cleared after animation completion");
    }

    #[test]
    fn test_render_frame_dev_tools_timing() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        orchestrator.set_target_fps(10000);
        
        // 渲染前
        orchestrator.dirty = true;
        orchestrator.last_frame_time = None;
        let result = orchestrator.render_frame();
        assert!(result, "render should succeed");
        
        // render_frame 在确认渲染后调用了 dev_tools.begin_frame() / end_frame()
        // 验证 DevTools 可用性（dev_tools 不应 panic）
        let _ = orchestrator.dev_tools().metrics();
    }

    #[test]
    fn test_render_frame_error_boundary_fatal_blocks() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        orchestrator.set_target_fps(10000);

        // 模拟 Fatal 错误 - ErrorBoundary 应阻止渲染
        let error = IrisError::new("Fatal test error", ErrorSource::Render, ErrorSeverity::Fatal);
        orchestrator.error_boundary.catch_error(error);
        assert!(!orchestrator.error_boundary.should_continue_rendering());

        // 即使 dirty 且 FPS 允许，ErrorBoundary 阻断优先
        orchestrator.last_frame_time = None;
        orchestrator.dirty = true;
        let result = orchestrator.render_frame();
        assert!(!result, "render_frame should be blocked by ErrorBoundary after Fatal error");

        // dirty 不应被清除（渲染被阻断）
        assert!(orchestrator.is_dirty(), "dirty should remain when render is blocked by ErrorBoundary");
    }

    #[test]
    fn test_render_frame_error_boundary_error_blocks() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        orchestrator.set_target_fps(10000);

        // Error 级别的错误也应阻止继续渲染
        let error = IrisError::new("Error test error", ErrorSource::Render, ErrorSeverity::Error);
        orchestrator.error_boundary.catch_error(error);
        assert!(!orchestrator.error_boundary.should_continue_rendering());

        orchestrator.last_frame_time = None;
        orchestrator.dirty = true;
        let result = orchestrator.render_frame();
        assert!(!result, "render_frame should be blocked by ErrorBoundary after Error severity");
    }

    #[test]
    fn test_render_frame_error_boundary_warning_allows() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        orchestrator.set_target_fps(10000);

        // Warning 级别的错误不应阻止渲染
        let error = IrisError::new("Warning test error", ErrorSource::Render, ErrorSeverity::Warning);
        orchestrator.error_boundary.catch_error(error);
        assert!(orchestrator.error_boundary.should_continue_rendering());

        orchestrator.last_frame_time = None;
        orchestrator.dirty = true;
        let result = orchestrator.render_frame();
        assert!(result, "render_frame should still render after Warning error");

        // dirty 应被正常清除
        assert!(!orchestrator.is_dirty(), "dirty should be cleared after successful render");
    }

    #[test]
    fn test_render_frame_after_error_boundary_reset() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        orchestrator.set_target_fps(10000);

        // 1. Fatal 错误阻断渲染
        let error = IrisError::new("Fatal error", ErrorSource::Render, ErrorSeverity::Fatal);
        orchestrator.error_boundary.catch_error(error);
        orchestrator.last_frame_time = None;
        orchestrator.dirty = true;
        assert!(!orchestrator.render_frame(), "should be blocked after Fatal error");

        // 2. 重置 ErrorBoundary
        orchestrator.error_boundary.reset();
        assert!(orchestrator.error_boundary.should_continue_rendering());

        // 3. 重置后应能正常渲染
        orchestrator.last_frame_time = None;
        let result = orchestrator.render_frame();
        assert!(result, "render should succeed after ErrorBoundary reset");
    }

    #[test]
    fn test_render_frame_active_animations_keep_dirty() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        orchestrator.set_target_fps(10000);

        // 启动一个不会瞬时完成的过渡动画（10 秒持续时间）
        let config = TransitionConfig {
            property: "opacity".to_string(),
            duration: 10000.0, // 10 秒，不会立即完成
            easing: EasingFunction::Linear,
            delay: 0.0,
        };
        orchestrator.start_transition(1, "opacity", 0.0, 1.0, &config);

        // 渲染一帧 - 动画仍在进行中
        orchestrator.last_frame_time = None;
        orchestrator.dirty = true;
        let result = orchestrator.render_frame();
        assert!(result, "render should succeed");

        // 有活动动画时 dirty 应保持为 true
        assert!(orchestrator.has_active_animations(), "animations should still be active");
        assert!(orchestrator.is_dirty(), "dirty should remain true when animations are active");
    }

    #[test]
    fn test_render_frame_fps_blocks_before_dirty_check() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        orchestrator.set_target_fps(1000);

        // 首次渲染（初始 dirty）
        orchestrator.last_frame_time = None;
        assert!(orchestrator.render_frame(), "first render should succeed");
        assert!(!orchestrator.is_dirty(), "dirty should be cleared");

        // 不重置时间戳 + 不标记 dirty
        // FPS 限制在 dirty 检查之前执行，所以即使 dirty=false，实际由 FPS 阻止
        let result = orchestrator.render_frame();
        assert!(!result, "render should be blocked (FPS before dirty check)");

        // 标记 dirty 后，FPS 仍阻止（时间未变）
        orchestrator.dirty = true;
        let result = orchestrator.render_frame();
        assert!(!result, "FPS should block even when dirty");

        // 重置时间戳绕过 FPS 后正常渲染
        orchestrator.last_frame_time = None;
        assert!(orchestrator.render_frame(), "render should succeed after FPS reset");
    }

    #[test]
    fn test_render_frame_gpu_wrapper_fps_and_dirty_respected() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        orchestrator.set_target_fps(10000);

        // 设置 dirty 和重置时间
        orchestrator.dirty = true;
        orchestrator.last_frame_time = None;

        // render_frame_gpu 应优先检查 GPU 渲染器是否存在
        // 不存在时返回 false，不影响 dirty
        let result = orchestrator.render_frame_gpu();
        assert!(!result, "render_frame_gpu should return false without GPU renderer");
        assert!(orchestrator.is_dirty(), "dirty should be preserved when render_frame_gpu returns early");

        // 验证 has_gpu_renderer
        assert!(!orchestrator.has_gpu_renderer(), "no GPU renderer should be set");
    }

    #[test]
    fn test_render_frame_infinite_keyframe_keeps_dirty() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        orchestrator.set_target_fps(10000);

        // 创建无限迭代关键帧动画（iteration_count=None 表示无限循环）
        let mut definition = KeyframesDefinition::new("infinite_spin");
        definition.add_keyframe(Keyframe::new(0.0).with_property("opacity", 0.0));
        definition.add_keyframe(Keyframe::new(1.0).with_property("opacity", 1.0));
        let anim = KeyframeAnimation::new(
            1, &definition, 1000.0, None,
            AnimationDirection::Normal, FillMode::None, 0.0,
        );
        orchestrator.start_keyframe_animation(anim);

        // 渲染多次，每次后 dirty 都应保持为 true（动画永不完成）
        for i in 0..3 {
            orchestrator.last_frame_time = None;
            orchestrator.dirty = true;
            let result = orchestrator.render_frame();
            assert!(result, "frame {} should render successfully", i);
            assert!(orchestrator.has_active_animations(),
                "infinite animation should remain active after frame {}", i);
            assert!(orchestrator.is_dirty(),
                "dirty should stay true for infinite animation after frame {}", i);
        }
    }

    #[test]
    fn test_render_frame_transition_with_delay_keeps_dirty() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        orchestrator.set_target_fps(10000);

        // 启动一个带 10 秒延迟的过渡动画
        // 延迟期间 transition 仍在 active_transitions 中，dirty 应保持
        let config = TransitionConfig {
            property: "opacity".to_string(),
            duration: 1000.0,
            easing: EasingFunction::Linear,
            delay: 10000.0, // 10 秒延迟
        };
        orchestrator.start_transition(1, "opacity", 0.0, 1.0, &config);

        // 渲染一帧 — 延迟期间，动画仍是活动的
        orchestrator.last_frame_time = None;
        orchestrator.dirty = true;
        let result = orchestrator.render_frame();
        assert!(result, "render should succeed");

        // 过渡尚未开始播放但有延迟，active_transitions 非空
        assert!(orchestrator.has_active_animations(),
            "transition with delay should still be considered active");
        assert!(orchestrator.is_dirty(),
            "dirty should stay true when transition has pending delay");
    }

    #[test]
    fn test_render_frame_after_error_boundary_recover() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        orchestrator.set_target_fps(10000);

        // 1. Warning 错误不应阻断渲染
        let warning = IrisError::new("Warning error", ErrorSource::Render, ErrorSeverity::Warning);
        orchestrator.error_boundary.catch_error(warning);
        assert!(orchestrator.error_boundary.should_continue_rendering());

        orchestrator.last_frame_time = None;
        orchestrator.dirty = true;
        assert!(orchestrator.render_frame(), "should render after Warning");

        // 2. 通过 recover() 恢复 Warning 错误
        assert!(orchestrator.error_boundary.recover().is_ok(),
            "recover should succeed for Warning");
        assert!(orchestrator.error_boundary.should_continue_rendering());

        // 3. 恢复后正常渲染
        orchestrator.last_frame_time = None;
        orchestrator.dirty = true;
        assert!(orchestrator.render_frame(), "should render after recover");
    }

   #[test]
    fn test_render_frame_error_boundary_fatal_cannot_recover() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        orchestrator.set_target_fps(10000);

        // 1. Fatal 错误阻断
        let fatal = IrisError::new("Fatal", ErrorSource::Render, ErrorSeverity::Fatal);
        orchestrator.error_boundary.catch_error(fatal);
        assert!(!orchestrator.error_boundary.should_continue_rendering());

        // 2. Fatal 错误无法通过 recover() 恢复
        assert!(orchestrator.error_boundary.recover().is_err(),
            "Fatal error should not be recoverable");
        assert!(!orchestrator.error_boundary.should_continue_rendering(),
            "should still be blocked after failed recover");

        // 3. 必须用 reset() 才能恢复
        orchestrator.error_boundary.reset();
        assert!(orchestrator.error_boundary.should_continue_rendering());

        orchestrator.last_frame_time = None;
        orchestrator.dirty = true;
        assert!(orchestrator.render_frame(), "should render after reset");
    }

    // ==========================================
    // E4-6INT: 事件系统集成测试
    // ==========================================

    /// 测试 1: 事件冒泡顺序 - 父子节点都注册了相同事件类型
    /// 验证子节点先被调用，父节点后被调用
    #[test]
    fn test_event_bubbling_simple() {
        use iris_layout::vdom::{VElement, VNode, VTree};

        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        // 注入 render helpers 使 __iris_invokeEventHandler 可用
        inject_render_helpers(orchestrator.js_runtime()).unwrap();
        orchestrator.set_target_fps(10000);

        // 创建 VTree: parent div("1") → child div("2")
        let mut parent_attrs = HashMap::new();
        parent_attrs.insert("_vnodeId".to_string(), "1".to_string());
        parent_attrs.insert("_eventTypes".to_string(), r#"{"click":true}"#.to_string());

        let mut child_attrs = HashMap::new();
        child_attrs.insert("_vnodeId".to_string(), "2".to_string());
        child_attrs.insert("_parentVnodeId".to_string(), "1".to_string());
        child_attrs.insert("_eventTypes".to_string(), r#"{"click":true}"#.to_string());

        let child = VNode::Element(VElement {
            tag: "div".to_string(),
            attrs: child_attrs,
            children: vec![],
            key: None,
        });

        let parent = VNode::Element(VElement {
            tag: "div".to_string(),
            attrs: parent_attrs,
            children: vec![child],
            key: None,
        });

        let vtree = VTree { root: parent };
        orchestrator.set_vtree(vtree);

        // 注册 JS 事件处理器，并使用额外标志追踪调用
        orchestrator.js_runtime().eval(r#"
            globalThis.callOrder = [];
            globalThis.parentCalledCount = 0;
            globalThis.childCalledCount = 0;

            globalThis.__iris_event_handlers['1'] = {
                'click': function(e) {
                    globalThis.parentCalledCount++;
                    globalThis.callOrder.push('parent');
                }
            };

            globalThis.__iris_event_handlers['2'] = {
                'click': function(e) {
                    globalThis.childCalledCount++;
                    globalThis.callOrder.push('child');
                }
            };
        "#).unwrap();

        // 验证 JS 事件处理器已正确注册
        let handlers_check = orchestrator.js_runtime()
            .eval("typeof globalThis.__iris_event_handlers['1']")
            .unwrap()
            .as_string()
            .map(|s| s.to_std_string_escaped())
            .unwrap_or_default();
        assert_eq!(handlers_check, "object", "Parent handler should be registered");

        let fn_check = orchestrator.js_runtime()
            .eval("typeof globalThis.__iris_event_handlers['1']['click']")
            .unwrap()
            .as_string()
            .map(|s| s.to_std_string_escaped())
            .unwrap_or_default();
        assert_eq!(fn_check, "function", "Parent click handler should be a function");

        // 验证 __iris_invokeEventHandler 可用
        let bridge_check = orchestrator.js_runtime()
            .eval("typeof globalThis.__iris_invokeEventHandler")
            .unwrap()
            .as_string()
            .map(|s| s.to_std_string_escaped())
            .unwrap_or_default();
        assert_eq!(bridge_check, "function", "__iris_invokeEventHandler should be available");

        // 触发点击事件
        orchestrator.handle_mouse_click(2, 100.0, 100.0, 0);

        // 执行渲染帧（会处理待处理事件）
        orchestrator.last_frame_time = None;
        let rendered = orchestrator.render_frame();
        assert!(rendered, "render_frame should execute");

        // 验证 child 被调用
        let child_count = orchestrator.js_runtime()
            .eval("globalThis.childCalledCount")
            .unwrap()
            .as_number()
            .unwrap_or(0.0) as i32;
        assert!(child_count >= 1, "Child should be called at least once, got: {}", child_count);

        // 验证 parent 被调用
        let parent_count = orchestrator.js_runtime()
            .eval("globalThis.parentCalledCount")
            .unwrap()
            .as_number()
            .unwrap_or(0.0) as i32;
        assert!(parent_count >= 1, "Parent should be called at least once, got: {}", parent_count);

        // 验证调用顺序：child (depth=1) → parent (depth=0)
        let result = orchestrator.js_runtime()
            .eval("JSON.stringify(globalThis.callOrder)")
            .unwrap();
        let order_str = result.as_string()
            .map(|s| s.to_std_string_escaped())
            .unwrap_or_default();
        assert_eq!(order_str, r#"["child","parent"]"#,
            "Expected child before parent in bubble order, got: {}", order_str);
    }

    /// 测试 2: 事件冒泡停止 - 子节点调用 stopPropagation
    /// 验证父节点不被调用
    #[test]
    fn test_event_bubbling_stop() {
        use iris_layout::vdom::{VElement, VNode, VTree};

        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        // 注入 render helpers 使 __iris_invokeEventHandler 可用
        inject_render_helpers(orchestrator.js_runtime()).unwrap();
        orchestrator.set_target_fps(10000);

        // 创建 VTree: parent div("1") → child div("2")
        let mut parent_attrs = HashMap::new();
        parent_attrs.insert("_vnodeId".to_string(), "1".to_string());
        parent_attrs.insert("_eventTypes".to_string(), r#"{"click":true}"#.to_string());

        let mut child_attrs = HashMap::new();
        child_attrs.insert("_vnodeId".to_string(), "2".to_string());
        child_attrs.insert("_parentVnodeId".to_string(), "1".to_string());
        child_attrs.insert("_eventTypes".to_string(), r#"{"click":true}"#.to_string());

        let child = VNode::Element(VElement {
            tag: "div".to_string(),
            attrs: child_attrs,
            children: vec![],
            key: None,
        });

        let parent = VNode::Element(VElement {
            tag: "div".to_string(),
            attrs: parent_attrs,
            children: vec![child],
            key: None,
        });

        let vtree = VTree { root: parent };
        orchestrator.set_vtree(vtree);

        // 注册 JS 事件处理器 - child 调用 stopPropagation
        orchestrator.js_runtime().eval(r#"
            globalThis.parentCalled = false;
            globalThis.childCalled = false;

            globalThis.__iris_event_handlers['1'] = {
                'click': function(e) {
                    globalThis.parentCalled = true;
                }
            };

            globalThis.__iris_event_handlers['2'] = {
                'click': function(e) {
                    globalThis.childCalled = true;
                    e.stopPropagation();
                }
            };
        "#).unwrap();

        // 触发点击事件
        orchestrator.handle_mouse_click(2, 100.0, 100.0, 0);

        // 执行渲染帧
        orchestrator.last_frame_time = None;
        let rendered = orchestrator.render_frame();
        assert!(rendered, "render_frame should execute");

        // 验证 child 被调用
        let child_called = orchestrator.js_runtime()
            .eval("globalThis.childCalled")
            .unwrap()
            .as_boolean()
            .unwrap_or(false);
        assert!(child_called, "Child handler should be called");

        // 验证 parent 未被调用（被 stopPropagation 阻止）
        let parent_called = orchestrator.js_runtime()
            .eval("globalThis.parentCalled")
            .unwrap()
            .as_boolean()
            .unwrap_or(false);
        assert!(!parent_called, "Parent handler should NOT be called after stopPropagation");
    }

    /// 测试 3: 组件渲染时 _vnodeId 在 VTree 中的传播
    #[test]
    fn test_component_render_with_vnode_ids() {
        use std::fs;
        use std::path::PathBuf;

        // 创建一个简单的 SFC 测试文件，验证 _vnodeId 在 VTree 中出现
        let test_vue = r#"
<template>
  <div class="parent">
    <p id="first">Hello</p>
    <span>World</span>
  </div>
</template>

<script>
export default {
  setup() {
    const msg = ref("Hello")
    return { msg }
  }
}
</script>
"#;

        let temp_path = PathBuf::from("test_vnode_ids.vue");
        fs::write(&temp_path, test_vue).unwrap();

        let mut orchestrator = RuntimeOrchestrator::new();
        assert!(orchestrator.initialize().is_ok());

        let result = orchestrator.load_sfc_with_vtree(&temp_path);
        assert!(result.is_ok(), "Failed to load SFC: {:?}", result);

        // 验证 VTree 存在
        let vtree = orchestrator.vtree().expect("VTree should be present");

        // 验证每个元素节点都有 _vnodeId
        fn check_vnode_ids(node: &iris_layout::vdom::VNode) {
            match node {
                iris_layout::vdom::VNode::Element(elem) => {
                    assert!(elem.attrs.contains_key("_vnodeId"),
                        "Element '{}' should have _vnodeId", elem.tag);
                    for child in &elem.children {
                        check_vnode_ids(child);
                    }
                }
                _ => {}
            }
        }
        check_vnode_ids(&vtree.root);

        // 验证根节点结构
        if let iris_layout::vdom::VNode::Element(elem) = &vtree.root {
            assert_eq!(elem.tag, "div", "Root should be a div");
            assert_eq!(elem.attrs.get("class"), Some(&"parent".to_string()));
            assert_eq!(elem.children.len(), 2, "Root should have 2 children");

            // 第一个子节点是 p#first
            if let iris_layout::vdom::VNode::Element(p) = &elem.children[0] {
                assert_eq!(p.tag, "p");
                assert_eq!(p.attrs.get("id"), Some(&"first".to_string()));
                assert!(p.attrs.contains_key("_vnodeId"));
            } else {
                panic!("First child should be an Element");
            }

            // 第二个子节点是 span
            if let iris_layout::vdom::VNode::Element(span) = &elem.children[1] {
                assert_eq!(span.tag, "span");
                assert!(span.attrs.contains_key("_vnodeId"));
            } else {
                panic!("Second child should be an Element");
            }
        } else {
            panic!("Root should be an Element node");
        }

        // 清理临时文件
        fs::remove_file(&temp_path).unwrap();
    }

    /// 测试 4: 直接验证 Rust→JS 事件桥接
    #[test]
    fn test_event_bridge_javascript() {
        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        // 注入 render helpers 使 __iris_invokeEventHandler 可用
        inject_render_helpers(orchestrator.js_runtime()).unwrap();

        // 1. 测试基本桥接：通过 __iris_invokeEventHandler 调用 handler
        orchestrator.js_runtime().eval(r#"
            globalThis.bridgeTestCalled = false;
            globalThis.bridgeTestPayload = null;

            globalThis.__iris_event_handlers['100'] = {
                'testevent': function(e) {
                    globalThis.bridgeTestCalled = true;
                    if (e.value) {
                        globalThis.bridgeTestPayload = e.value;
                    }
                }
            };
        "#).unwrap();

        // 2. 调用桥接函数（模拟 Rust 调用）
        let result = orchestrator.js_runtime().eval(
            "globalThis.__iris_invokeEventHandler('100', 'testevent', null)"
        ).unwrap();
        assert!(!result.as_boolean().unwrap_or(true),
            "Bridge should return false when propagation not stopped");

        let called = orchestrator.js_runtime()
            .eval("globalThis.bridgeTestCalled")
            .unwrap()
            .as_boolean()
            .unwrap_or(false);
        assert!(called, "JS event handler should be called via bridge");

        // 3. 测试带数据的事件桥接
        orchestrator.js_runtime().eval("globalThis.bridgeTestCalled = false;").unwrap();
        let result2 = orchestrator.js_runtime().eval(
            r#"globalThis.__iris_invokeEventHandler('100', 'testevent', {value: 42})"#
        ).unwrap();
        assert!(!result2.as_boolean().unwrap_or(true),
            "Bridge should return false when propagation not stopped");

        let payload = orchestrator.js_runtime()
            .eval("globalThis.bridgeTestPayload")
            .unwrap();
        if let Some(num) = payload.as_number() {
            assert!((num - 42.0).abs() < f32::EPSILON as f64,
                "Payload should be 42, got: {}", num);
        } else {
            panic!("Expected numeric payload");
        }

        // 4. 测试 stopPropagation 返回 true
        orchestrator.js_runtime().eval(r#"
            globalThis.__iris_event_handlers['101'] = {
                'click': function(e) {
                    e.stopPropagation();
                }
            };
        "#).unwrap();

        let result3 = orchestrator.js_runtime().eval(
            "globalThis.__iris_invokeEventHandler('101', 'click', null)"
        ).unwrap();
        assert!(result3.as_boolean().unwrap_or(false),
            "Bridge should return true when stopPropagation is called");

        // 5. 测试不存在的 handler 返回 false
        let result4 = orchestrator.js_runtime().eval(
            "globalThis.__iris_invokeEventHandler('999', 'nonexistent', null)"
        ).unwrap();
        assert!(!result4.as_boolean().unwrap_or(true),
            "Bridge should return false for nonexistent handler");
    }

    /// E5-1: 测试通过 render_frame 自动检测响应式脏标记并更新 VTree
    #[test]
    fn test_reactive_auto_update_via_render_frame() {
        use std::fs;
        use std::path::PathBuf;

        let test_vue = r#"
<template>
  <div class="counter">
    <p>Count: {{ count }}</p>
  </div>
</template>

<script>
export default {
  setup() {
    const count = ref(42)
    return { count }
  }
}
</script>
"#;

        let temp_path = PathBuf::from("test_reactive_auto.vue");
        fs::write(&temp_path, test_vue).unwrap();

        let mut orchestrator = RuntimeOrchestrator::new();
        assert!(orchestrator.initialize().is_ok());

        // 加载 SFC
        let result = orchestrator.load_sfc_with_vtree(&temp_path);
        assert!(result.is_ok(), "Failed to load SFC: {:?}", result);

        // 验证初始 VTree 包含 count=42
        let vtree = orchestrator.vtree().expect("VTree should be present");
        let initial_text = extract_vtree_text(&vtree);
        assert!(initial_text.contains("42"), "Initial text should contain 42");

        // 修改响应式数据
        let js_result = orchestrator.js_runtime().eval("count = 99");
        assert!(js_result.is_ok(), "Failed to set count: {:?}", js_result);

        // 验证脏标记已设置
        assert!(check_reactive_dirty(orchestrator.js_runtime()),
            "__render_dirty should be true after data change");

        // 调用 render_frame，它内部会通过 process_pending_events 检测脏标记并更新
        orchestrator.last_frame_time = None;
        let rendered = orchestrator.render_frame();
        assert!(rendered, "render_frame should execute");

        // 验证脏标记已被清除
        assert!(!check_reactive_dirty(orchestrator.js_runtime()),
            "__render_dirty should be cleared after process_pending_events");

        // 验证 VTree 已自动更新
        let updated_vtree = orchestrator.vtree().expect("Updated VTree should be present");
        let updated_text = extract_vtree_text(&updated_vtree);
        assert!(updated_text.contains("99"),
            "Text should contain 99 after auto-update, got: '{}'", updated_text);
        assert!(!updated_text.contains("42"),
            "Text should NOT contain 42 after auto-update, got: '{}'", updated_text);

        // 清理临时文件
        fs::remove_file(&temp_path).unwrap();
    }

    /// E5-2: 测试响应式更新产生正确的 VTree diff patches
    #[test]
    fn test_reactive_vtree_diff_auto() {
        use std::fs;
        use std::path::PathBuf;

        let test_vue = r#"
<template>
  <div class="counter">
    <p>Count: {{ count }}</p>
    <span>Static text</span>
  </div>
</template>

<script>
export default {
  setup() {
    const count = ref(42)
    const message = ref("Hello")
    return { count, message }
  }
}
</script>
"#;

        let temp_path = PathBuf::from("test_diff_auto.vue");
        fs::write(&temp_path, test_vue).unwrap();

        let mut orchestrator = RuntimeOrchestrator::new();
        assert!(orchestrator.initialize().is_ok());

        // 加载 SFC 并生成 DOM 树（用于 diff 验证）
        let result = orchestrator.load_sfc_with_vtree(&temp_path);
        assert!(result.is_ok(), "Failed to load SFC: {:?}", result);
        let dom_result = orchestrator.compute_layout();
        assert!(dom_result.is_ok(), "Failed to compute layout: {:?}", dom_result);

        // 初始时 old_vtree 为 None
        assert!(orchestrator.old_vtree.is_none(), "old_vtree should be None initially");

        // 修改响应式数据
        let js_result = orchestrator.js_runtime().eval("count = 99");
        assert!(js_result.is_ok());

        // 验证脏标记
        assert!(check_reactive_dirty(orchestrator.js_runtime()));

        // 调用 render_frame 触发自动更新
        orchestrator.last_frame_time = None;
        let rendered = orchestrator.render_frame();
        assert!(rendered);

        // 验证 old_vtree 有值（第一次更新后保存了旧引用）
        assert!(orchestrator.old_vtree.is_some(), "old_vtree should be set after update");

        // 验证 VTree 内容更新
        let updated_vtree = orchestrator.vtree().expect("Updated VTree should be present");
        match &updated_vtree.root {
            iris_layout::vdom::VNode::Element(elem) => {
                assert_eq!(elem.children.len(), 2, "Should still have 2 children");

                // p 标签文本已更新
                if let iris_layout::vdom::VNode::Element(p) = &elem.children[0] {
                    if let iris_layout::vdom::VNode::Text(text) = &p.children[0] {
                        assert!(text.contains("99"), "Text should contain 99, got: '{}'", text);
                        assert!(!text.contains("42"), "Text should NOT contain 42");
                    }
                }

                // span 标签静态文本未受影响
                if let iris_layout::vdom::VNode::Element(span) = &elem.children[1] {
                    if let iris_layout::vdom::VNode::Text(text) = &span.children[0] {
                        assert_eq!(text, "Static text");
                    }
                }
            }
            _ => panic!("Root should be an Element node"),
        }

        // 第二次响应式更新：修改被模板使用的变量
        let js_result = orchestrator.js_runtime().eval("count = 100");
        assert!(js_result.is_ok());
        assert!(check_reactive_dirty(orchestrator.js_runtime()),
            "__render_dirty should be set after second count change");

        orchestrator.last_frame_time = None;
        let rendered = orchestrator.render_frame();
        assert!(rendered);

        // 验证 old_vtree 在多次更新后仍有效
        assert!(orchestrator.old_vtree.is_some(),
            "old_vtree should still be set after second update");

        // 验证 DOM 树仍然有效
        let dom_tree = orchestrator.dom_tree.as_ref().expect("DOM tree should exist");
        match &dom_tree.node_type {
            iris_layout::dom::NodeType::Element(tag) => {
                assert_eq!(tag, "div");
                assert_eq!(dom_tree.children.len(), 2);
            }
            _ => panic!("DOM root should be Element"),
        }

        // 验证 count 已更新为 100
        let vtree = orchestrator.vtree().expect("VTree should be present");
        match &vtree.root {
            iris_layout::vdom::VNode::Element(elem) => {
                if let iris_layout::vdom::VNode::Element(p) = &elem.children[0] {
                    if let iris_layout::vdom::VNode::Text(text) = &p.children[0] {
                        assert!(text.contains("100"),
                            "Text should contain 100 after second update, got: '{}'", text);
                    }
                }
            }
            _ => {}
        }

        // 清理临时文件
        fs::remove_file(&temp_path).unwrap();
    }

    /// 测试 handle_focus: 验证 Focus 事件通过 Rust 监听器
    #[test]
    fn test_handle_focus_event() {
        use std::cell::RefCell;
        use std::rc::Rc;

        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();

        let focused = Rc::new(RefCell::new(false));
        let focused_clone = focused.clone();

        orchestrator.add_event_listener(
            1,
            EventType::Focus,
            Box::new(move |_event| {
                *focused_clone.borrow_mut() = true;
            }),
            false,
        );

        orchestrator.handle_focus(1);
        orchestrator.mark_dirty();
        orchestrator.render_frame();

        assert!(*focused.borrow(), "Focus event should trigger listener");
    }

    /// 测试 handle_blur: 验证 Blur 事件通过 Rust 监听器
    #[test]
    fn test_handle_blur_event() {
        use std::cell::RefCell;
        use std::rc::Rc;

        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();

        let blurred = Rc::new(RefCell::new(false));
        let blurred_clone = blurred.clone();

        orchestrator.add_event_listener(
            1,
            EventType::Blur,
            Box::new(move |_event| {
                *blurred_clone.borrow_mut() = true;
            }),
            false,
        );

        orchestrator.handle_blur(1);
        orchestrator.mark_dirty();
        orchestrator.render_frame();

        assert!(*blurred.borrow(), "Blur event should trigger listener");
    }

    /// 测试 focus/blur 事件 JS 桥接: 验证数据正确传递到 JS 侧
    #[test]
    fn test_focus_blur_javascript_bridge() {
        use iris_layout::vdom::{VElement, VNode, VTree};
        use std::collections::HashMap;

        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        inject_render_helpers(orchestrator.js_runtime()).unwrap();
        orchestrator.set_target_fps(10000);

        // 创建 VTree: div(1) 包含 focus 和 blur 事件
        let mut div_attrs = HashMap::new();
        div_attrs.insert("_vnodeId".to_string(), "1".to_string());
        div_attrs.insert("_eventTypes".to_string(), r#"{"focus":true,"blur":true}"#.to_string());

        let div_node = VNode::Element(VElement {
            tag: "div".to_string(),
            attrs: div_attrs,
            children: vec![],
            key: None,
        });

        let vtree = VTree { root: div_node };
        orchestrator.set_vtree(vtree);

        // 注册 JS 事件处理器
        orchestrator.js_runtime().eval(r#"
            globalThis.focusReceived = false;
            globalThis.blurReceived = false;
            globalThis.__iris_event_handlers['1'] = {
                'focus': function(e) {
                    globalThis.focusReceived = true;
                },
                'blur': function(e) {
                    globalThis.blurReceived = true;
                }
            };
        "#).unwrap();

        // 测试 focus
        orchestrator.handle_focus(1);
        orchestrator.render_frame();
        let focus_received = orchestrator.js_runtime()
            .eval("globalThis.focusReceived")
            .unwrap()
            .as_boolean()
            .unwrap_or(false);
        assert!(focus_received, "JS should receive focus event");

        // 测试 blur
        orchestrator.handle_blur(1);
        orchestrator.render_frame();
        let blur_received = orchestrator.js_runtime()
            .eval("globalThis.blurReceived")
            .unwrap()
            .as_boolean()
            .unwrap_or(false);
        assert!(blur_received, "JS should receive blur event");
    }

    /// 测试 handle_scroll: 验证 Scroll 事件通过 Rust 监听器
    #[test]
    fn test_handle_scroll_event() {
        use std::cell::RefCell;
        use std::rc::Rc;

        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();

        let scroll_data = Rc::new(RefCell::new(None));
        let scroll_data_clone = scroll_data.clone();

        orchestrator.add_event_listener(
            1,
            EventType::Scroll,
            Box::new(move |event| {
                if let iris_dom::event::EventData::Custom(data) = &event.data {
                    *scroll_data_clone.borrow_mut() = Some(data.clone());
                }
            }),
            false,
        );

        orchestrator.handle_scroll(1, 100.0, 200.0);
        orchestrator.mark_dirty();
        orchestrator.render_frame();

        let data = scroll_data.borrow();
        assert!(data.is_some(), "Scroll event should trigger listener");
        if let Some(ref json) = *data {
            assert!(json.contains("100"), "Should contain scrollLeft");
            assert!(json.contains("200"), "Should contain scrollTop");
        }
    }

    /// 测试 scroll 事件 JS 桥接: 验证 scrollLeft/scrollTop 正确传递
    #[test]
    fn test_scroll_javascript_bridge() {
        use iris_layout::vdom::{VElement, VNode, VTree};
        use std::collections::HashMap;

        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        inject_render_helpers(orchestrator.js_runtime()).unwrap();
        orchestrator.set_target_fps(10000);

        // 创建 VTree: div(1) 包含 scroll 事件
        let mut div_attrs = HashMap::new();
        div_attrs.insert("_vnodeId".to_string(), "1".to_string());
        div_attrs.insert("_eventTypes".to_string(), r#"{"scroll":true}"#.to_string());

        let div_node = VNode::Element(VElement {
            tag: "div".to_string(),
            attrs: div_attrs,
            children: vec![],
            key: None,
        });

        let vtree = VTree { root: div_node };
        orchestrator.set_vtree(vtree);

        // 注册 JS scroll 处理器
        orchestrator.js_runtime().eval(r#"
            globalThis.scrollReceived = false;
            globalThis.scrollLeft = 0;
            globalThis.scrollTop = 0;
            globalThis.__iris_event_handlers['1'] = {
                'scroll': function(e) {
                    globalThis.scrollReceived = true;
                    globalThis.scrollLeft = e.target.scrollLeft;
                    globalThis.scrollTop = e.target.scrollTop;
                }
            };
        "#).unwrap();

        // 触发 scroll 事件
        orchestrator.handle_scroll(1, 50.0, 150.0);
        orchestrator.render_frame();

        let scroll_received = orchestrator.js_runtime()
            .eval("globalThis.scrollReceived")
            .unwrap()
            .as_boolean()
            .unwrap_or(false);
        assert!(scroll_received, "JS should receive scroll event");

        let scroll_left = orchestrator.js_runtime()
            .eval("globalThis.scrollLeft")
            .unwrap()
            .as_number()
            .unwrap_or(0.0);
        assert!(
            (scroll_left - 50.0).abs() < f64::EPSILON,
            "scrollLeft should be 50, got: {}", scroll_left
        );

        let scroll_top = orchestrator.js_runtime()
            .eval("globalThis.scrollTop")
            .unwrap()
            .as_number()
            .unwrap_or(0.0);
        assert!(
            (scroll_top - 150.0).abs() < f64::EPSILON,
            "scrollTop should be 150, got: {}", scroll_top
        );
   }

    /// 测试 handle_submit: 验证 Submit 事件通过 Rust 监听器
    #[test]
    fn test_handle_submit_event() {
        use std::cell::RefCell;
        use std::rc::Rc;

        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();

        let submit_fired = Rc::new(RefCell::new(false));
        let submit_fired_clone = submit_fired.clone();

        orchestrator.add_event_listener(
            1,
            EventType::Submit,
            Box::new(move |_| {
                *submit_fired_clone.borrow_mut() = true;
            }),
            false,
        );

        orchestrator.handle_submit(1);
        orchestrator.mark_dirty();
        orchestrator.render_frame();

        assert!(
            *submit_fired.borrow(),
            "Submit event should trigger Rust listener"
        );
    }

    /// 测试 submit 事件 JS 桥接 — 验证提交事件正确传递到 JS 处理器
    #[test]
    fn test_submit_javascript_bridge() {
        use iris_layout::vdom::{VElement, VNode, VTree};
        use std::collections::HashMap;

        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        inject_render_helpers(orchestrator.js_runtime()).unwrap();
        orchestrator.set_target_fps(10000);

        // 创建 VTree: div(1) 包含 submit 事件
        let mut div_attrs = HashMap::new();
        div_attrs.insert("_vnodeId".to_string(), "1".to_string());
        div_attrs.insert("_eventTypes".to_string(), r#"{"submit":true}"#.to_string());

        let div_node = VNode::Element(VElement {
            tag: "form".to_string(),
            attrs: div_attrs,
            children: vec![],
            key: None,
        });

        let vtree = VTree { root: div_node };
        orchestrator.set_vtree(vtree);

        // 注册 JS submit 处理器
        orchestrator.js_runtime().eval(r#"
            globalThis.submitReceived = false;
            globalThis.__iris_event_handlers['1'] = {
                'submit': function(e) {
                    globalThis.submitReceived = true;
                    globalThis.submitTargetId = e.target.id;
                }
            };
        "#).unwrap();

        // 触发 submit 事件
        orchestrator.handle_submit(1);
        orchestrator.render_frame();

        let submit_received = orchestrator.js_runtime()
            .eval("globalThis.submitReceived")
            .unwrap()
            .as_boolean()
            .unwrap_or(false);
        assert!(submit_received, "JS should receive submit event");
    }

    /// 测试 handle_wheel: 验证 Wheel 事件通过 Rust 监听器
    #[test]
    fn test_handle_wheel_event() {
        use std::cell::RefCell;
        use std::rc::Rc;

        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();

        let wheel_data = Rc::new(RefCell::new(None));
        let wheel_data_clone = wheel_data.clone();

        orchestrator.add_event_listener(
            1,
            EventType::Wheel,
            Box::new(move |event| {
                if let iris_dom::event::EventData::Custom(data) = &event.data {
                    *wheel_data_clone.borrow_mut() = Some(data.clone());
                }
            }),
            false,
        );

        orchestrator.handle_wheel(1, 10.0, 20.0, 0.0);
        orchestrator.mark_dirty();
        orchestrator.render_frame();

        let data = wheel_data.borrow();
        assert!(data.is_some(), "Wheel event should trigger listener");
        if let Some(ref json) = *data {
            assert!(json.contains("10"), "Should contain deltaX");
            assert!(json.contains("20"), "Should contain deltaY");
        }
    }

    /// 测试 wheel 事件 JS 桥接
    #[test]
    fn test_wheel_javascript_bridge() {
        use iris_layout::vdom::{VElement, VNode, VTree};
        use std::collections::HashMap;

        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        inject_render_helpers(orchestrator.js_runtime()).unwrap();
        orchestrator.set_target_fps(10000);

        let mut div_attrs = HashMap::new();
        div_attrs.insert("_vnodeId".to_string(), "1".to_string());
        div_attrs.insert("_eventTypes".to_string(), r#"{"wheel":true}"#.to_string());

        let div_node = VNode::Element(VElement {
            tag: "div".to_string(),
            attrs: div_attrs,
            children: vec![],
            key: None,
        });

        let vtree = VTree { root: div_node };
        orchestrator.set_vtree(vtree);

        orchestrator.js_runtime().eval(r#"
            globalThis.wheelReceived = false;
            globalThis.__iris_event_handlers['1'] = {
                'wheel': function(e) {
                    globalThis.wheelReceived = true;
                    globalThis.wheelDX = e.deltaX;
                    globalThis.wheelDY = e.deltaY;
                }
            };
        "#).unwrap();

        orchestrator.handle_wheel(1, 120.0, 240.0, 0.0);
        orchestrator.render_frame();

        let wheel_received = orchestrator.js_runtime()
            .eval("globalThis.wheelReceived")
            .unwrap()
            .as_boolean()
            .unwrap_or(false);
        assert!(wheel_received, "JS should receive wheel event");

        let delta_x = orchestrator.js_runtime()
            .eval("globalThis.wheelDX")
            .unwrap()
            .as_number()
            .unwrap_or(0.0);
        assert!(
            (delta_x - 120.0).abs() < f64::EPSILON,
            "deltaX should be 120, got: {}", delta_x
        );
    }

    /// 测试 handle_context_menu: 验证 ContextMenu 事件通过 Rust 监听器
    #[test]
    fn test_handle_context_menu_event() {
        use std::cell::RefCell;
        use std::rc::Rc;

        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();

        let menu_fired = Rc::new(RefCell::new(false));
        let menu_fired_clone = menu_fired.clone();

        orchestrator.add_event_listener(
            1,
            EventType::ContextMenu,
            Box::new(move |_| {
                *menu_fired_clone.borrow_mut() = true;
            }),
            false,
        );

        orchestrator.handle_context_menu(1, 100.0, 200.0);
        orchestrator.mark_dirty();
        orchestrator.render_frame();

        assert!(
            *menu_fired.borrow(),
            "ContextMenu event should trigger Rust listener"
        );
    }

    /// 测试 contextmenu 事件 JS 桥接
    #[test]
    fn test_context_menu_javascript_bridge() {
        use iris_layout::vdom::{VElement, VNode, VTree};
        use std::collections::HashMap;

        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        inject_render_helpers(orchestrator.js_runtime()).unwrap();
        orchestrator.set_target_fps(10000);

        let mut div_attrs = HashMap::new();
        div_attrs.insert("_vnodeId".to_string(), "1".to_string());
        div_attrs.insert("_eventTypes".to_string(), r#"{"contextmenu":true}"#.to_string());

        let div_node = VNode::Element(VElement {
            tag: "div".to_string(),
            attrs: div_attrs,
            children: vec![],
            key: None,
        });

        let vtree = VTree { root: div_node };
        orchestrator.set_vtree(vtree);

        orchestrator.js_runtime().eval(r#"
            globalThis.contextMenuReceived = false;
            globalThis.__iris_event_handlers['1'] = {
                'contextmenu': function(e) {
                    globalThis.contextMenuReceived = true;
                }
            };
        "#).unwrap();

        orchestrator.handle_context_menu(1, 150.0, 250.0);
        orchestrator.render_frame();

        let menu_received = orchestrator.js_runtime()
            .eval("globalThis.contextMenuReceived")
            .unwrap()
            .as_boolean()
            .unwrap_or(false);
        assert!(menu_received, "JS should receive contextmenu event");
    }

    /// 测试 handle_touch_start: 验证 TouchStart 事件通过 Rust 监听器
    #[test]
    fn test_handle_touch_start_event() {
        use std::cell::RefCell;
        use std::rc::Rc;

        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();

        let touch_fired = Rc::new(RefCell::new(false));
        let touch_fired_clone = touch_fired.clone();

        orchestrator.add_event_listener(
            1,
            EventType::TouchStart,
            Box::new(move |_| {
                *touch_fired_clone.borrow_mut() = true;
            }),
            false,
        );

        orchestrator.handle_touch_start(1, "[{\"x\":10,\"y\":20}]");
        orchestrator.mark_dirty();
        orchestrator.render_frame();

        assert!(
            *touch_fired.borrow(),
            "TouchStart event should trigger Rust listener"
        );
    }

    /// 测试 handle_touch_move: 验证 TouchMove 事件通过 Rust 监听器
    #[test]
    fn test_handle_touch_move_event() {
        use std::cell::RefCell;
        use std::rc::Rc;

        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();

        let touch_fired = Rc::new(RefCell::new(false));
        let touch_fired_clone = touch_fired.clone();

        orchestrator.add_event_listener(
            1,
            EventType::TouchMove,
            Box::new(move |_| {
                *touch_fired_clone.borrow_mut() = true;
            }),
            false,
        );

        orchestrator.handle_touch_move(1, "[{\"x\":30,\"y\":40}]");
        orchestrator.mark_dirty();
        orchestrator.render_frame();

        assert!(
            *touch_fired.borrow(),
            "TouchMove event should trigger Rust listener"
        );
    }

    /// 测试 handle_touch_end: 验证 TouchEnd 事件通过 Rust 监听器
    #[test]
    fn test_handle_touch_end_event() {
        use std::cell::RefCell;
        use std::rc::Rc;

        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();

        let touch_fired = Rc::new(RefCell::new(false));
        let touch_fired_clone = touch_fired.clone();

        orchestrator.add_event_listener(
            1,
            EventType::TouchEnd,
            Box::new(move |_| {
                *touch_fired_clone.borrow_mut() = true;
            }),
            false,
        );

        orchestrator.handle_touch_end(1, "[]");
        orchestrator.mark_dirty();
        orchestrator.render_frame();

        assert!(
            *touch_fired.borrow(),
            "TouchEnd event should trigger Rust listener"
        );
    }

    /// 测试 touch 事件 JS 桥接
    #[test]
    fn test_touch_javascript_bridge() {
        use iris_layout::vdom::{VElement, VNode, VTree};
        use std::collections::HashMap;

        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        inject_render_helpers(orchestrator.js_runtime()).unwrap();
        orchestrator.set_target_fps(10000);

        let mut div_attrs = HashMap::new();
        div_attrs.insert("_vnodeId".to_string(), "1".to_string());
        div_attrs.insert("_eventTypes".to_string(), r#"{"touchstart":true}"#.to_string());

        let div_node = VNode::Element(VElement {
            tag: "div".to_string(),
            attrs: div_attrs,
            children: vec![],
            key: None,
        });

        let vtree = VTree { root: div_node };
        orchestrator.set_vtree(vtree);

        orchestrator.js_runtime().eval(r#"
            globalThis.touchReceived = false;
            globalThis.__iris_event_handlers['1'] = {
                'touchstart': function(e) {
                    globalThis.touchReceived = true;
                    globalThis.touchCount = e.touches.length;
                }
            };
        "#).unwrap();

        orchestrator.handle_touch_start(1, "[{\"x\":50,\"y\":60}]");
        orchestrator.render_frame();

        let touch_received = orchestrator.js_runtime()
            .eval("globalThis.touchReceived")
            .unwrap()
            .as_boolean()
            .unwrap_or(false);
        assert!(touch_received, "JS should receive touchstart event");

        let touch_count = orchestrator.js_runtime()
            .eval("globalThis.touchCount")
            .unwrap()
            .as_number()
            .unwrap_or(0.0);
        assert!(
            (touch_count - 1.0).abs() < f64::EPSILON,
            "Should have 1 touch point, got: {}", touch_count
        );
    }

    /// 测试 handle_mouse_move: 验证 MouseMove 事件通过 Rust 监听器
    #[test]
    fn test_handle_mouse_move_event() {
        use std::cell::RefCell;
        use std::rc::Rc;

        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();

        let move_data = Rc::new(RefCell::new(None));
        let move_data_clone = move_data.clone();

        orchestrator.add_event_listener(
            1,
            EventType::MouseMove,
            Box::new(move |event| {
                if let iris_dom::event::EventData::Mouse(m) = &event.data {
                    *move_data_clone.borrow_mut() = Some((m.x, m.y));
                }
            }),
            false,
        );

        orchestrator.handle_mouse_move(1, 300.0, 400.0);
        orchestrator.mark_dirty();
        orchestrator.render_frame();

        let data = move_data.borrow();
        assert!(data.is_some(), "MouseMove event should trigger listener");
        if let Some((x, y)) = *data {
            assert!((x - 300.0).abs() < f32::EPSILON);
            assert!((y - 400.0).abs() < f32::EPSILON);
        }
    }

    /// 测试 handle_mouse_enter: 验证 MouseEnter 事件
    #[test]
    fn test_handle_mouse_enter_event() {
        use std::cell::RefCell;
        use std::rc::Rc;

        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();

        let enter_data = Rc::new(RefCell::new(false));
        let enter_data_clone = enter_data.clone();

        orchestrator.add_event_listener(
            1,
            EventType::MouseEnter,
            Box::new(move |_event| {
                *enter_data_clone.borrow_mut() = true;
            }),
            false,
        );

        orchestrator.handle_mouse_enter(1, 50.0, 60.0);
        orchestrator.mark_dirty();
        orchestrator.render_frame();

        assert!(*enter_data.borrow(), "MouseEnter event should trigger listener");
    }

    /// 测试 handle_mouse_leave: 验证 MouseLeave 事件
    #[test]
    fn test_handle_mouse_leave_event() {
        use std::cell::RefCell;
        use std::rc::Rc;

        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();

        let leave_data = Rc::new(RefCell::new(false));
        let leave_data_clone = leave_data.clone();

        orchestrator.add_event_listener(
            1,
            EventType::MouseLeave,
            Box::new(move |_event| {
                *leave_data_clone.borrow_mut() = true;
            }),
            false,
        );

        orchestrator.handle_mouse_leave(1, 70.0, 80.0);
        orchestrator.mark_dirty();
        orchestrator.render_frame();

        assert!(*leave_data.borrow(), "MouseLeave event should trigger listener");
    }

    /// 测试 mouse 事件 JS 桥接: 验证三种鼠标事件正确分发到 JS 处理器
    #[test]
    fn test_mouse_events_javascript_bridge() {
        use iris_layout::vdom::{VElement, VNode, VTree};
        use std::collections::HashMap;

        let mut orchestrator = RuntimeOrchestrator::new();
        orchestrator.initialize().unwrap();
        inject_render_helpers(orchestrator.js_runtime()).unwrap();
        orchestrator.set_target_fps(10000);

        // 创建 VTree: div(1) 包含三种鼠标事件
        let mut div_attrs = HashMap::new();
        div_attrs.insert("_vnodeId".to_string(), "1".to_string());
        div_attrs.insert("_eventTypes".to_string(), r#"{"mousemove":true,"mouseenter":true,"mouseleave":true}"#.to_string());

        let div_node = VNode::Element(VElement {
            tag: "div".to_string(),
            attrs: div_attrs,
            children: vec![],
            key: None,
        });

        let vtree = VTree { root: div_node };
        orchestrator.set_vtree(vtree);

        // 注册 JS 事件处理器
        orchestrator.js_runtime().eval(r#"
            globalThis.mouseMoveReceived = false;
            globalThis.mouseEnterReceived = false;
            globalThis.mouseLeaveReceived = false;
            globalThis.__iris_event_handlers['1'] = {
                'mousemove': function(e) {
                    globalThis.mouseMoveReceived = true;
                },
                'mouseenter': function(e) {
                    globalThis.mouseEnterReceived = true;
                },
                'mouseleave': function(e) {
                    globalThis.mouseLeaveReceived = true;
                }
            };
        "#).unwrap();

        // 测试 mousemove
        orchestrator.handle_mouse_move(1, 100.0, 200.0);
        orchestrator.render_frame();
        assert!(
            orchestrator.js_runtime()
                .eval("globalThis.mouseMoveReceived")
                .unwrap()
                .as_boolean()
                .unwrap_or(false),
            "JS should receive mousemove event"
        );

        // 测试 mouseenter
        orchestrator.handle_mouse_enter(1, 100.0, 200.0);
        orchestrator.render_frame();
        assert!(
            orchestrator.js_runtime()
                .eval("globalThis.mouseEnterReceived")
                .unwrap()
                .as_boolean()
                .unwrap_or(false),
            "JS should receive mouseenter event"
        );

        // 测试 mouseleave
        orchestrator.handle_mouse_leave(1, 300.0, 400.0);
        orchestrator.render_frame();
        assert!(
            orchestrator.js_runtime()
                .eval("globalThis.mouseLeaveReceived")
                .unwrap()
                .as_boolean()
                .unwrap_or(false),
            "JS should receive mouseleave event"
        );
    }

    /// F2-1: 测试 v-if 条件渲染的响应式更新（true → false 节点隐藏）
    #[test]
    fn test_vif_reactive_update() {
        use std::fs;
        use std::path::PathBuf;

        let test_vue = r#"
<template>
  <div class="vif-test">
    <p v-if="show">Visible content</p>
    <span v-else>Hidden alternative</span>
  </div>
</template>

<script>
export default {
  setup() {
    const show = ref(true)
    return { show }
  }
}
</script>
"#;

        let temp_path = PathBuf::from("test_vif_reactive.vue");
        fs::write(&temp_path, test_vue).unwrap();

        let mut orchestrator = RuntimeOrchestrator::new();
        assert!(orchestrator.initialize().is_ok());

        // 加载 SFC
        let result = orchestrator.load_sfc_with_vtree(&temp_path);
        assert!(result.is_ok(), "Failed to load SFC: {:?}", result);

        // 验证初始 VTree 包含 v-if 可见内容
        let vtree = orchestrator.vtree().expect("VTree should be present");
        let text = extract_vtree_text(&vtree);
        assert!(text.contains("Visible"), "Initial VTree should show visible content, got: '{}'", text);

        // 修改 show = false 触发 v-if → v-else 切换
        let js_result = orchestrator.js_runtime().eval("show = false");
        assert!(js_result.is_ok(), "Failed to set show=false: {:?}", js_result);

        // 调用 render_frame 触发响应式更新
        orchestrator.last_frame_time = None;
        let rendered = orchestrator.render_frame();
        assert!(rendered, "render_frame should execute");

        // 验证 VTree 已切换到 v-else 内容
        let updated_vtree = orchestrator.vtree().expect("Updated VTree should be present");
        let updated_text = extract_vtree_text(&updated_vtree);
        assert!(updated_text.contains("Hidden"),
            "After show=false, VTree should show hidden alternative, got: '{}'", updated_text);
        assert!(!updated_text.contains("Visible"),
            "After show=false, VTree should NOT contain visible content, got: '{}'", updated_text);

        // 清理临时文件
        fs::remove_file(&temp_path).unwrap();
    }

    /// F2-2: 测试 v-for 列表渲染的响应式更新（数组添加元素）
    #[test]
    fn test_vfor_reactive_update() {
        use std::fs;
        use std::path::PathBuf;

        let test_vue = r#"
<template>
  <div class="vfor-test">
    <ul>
      <li v-for="item in items" :key="item.id">{{ item.name }}</li>
    </ul>
  </div>
</template>

<script>
export default {
  setup() {
    const items = ref([
      { id: 1, name: "Apple" },
      { id: 2, name: "Banana" },
    ])
    return { items }
  }
}
</script>
"#;

        let temp_path = PathBuf::from("test_vfor_reactive.vue");
        fs::write(&temp_path, test_vue).unwrap();

        let mut orchestrator = RuntimeOrchestrator::new();
        assert!(orchestrator.initialize().is_ok());

        // 加载 SFC
        let result = orchestrator.load_sfc_with_vtree(&temp_path);
        assert!(result.is_ok(), "Failed to load SFC: {:?}", result);

        // 验证初始 VTree 包含 2 个列表项
        let vtree = orchestrator.vtree().expect("VTree should be present");
        let initial_text = extract_vtree_text(&vtree);
        assert!(initial_text.contains("Apple"), "Initial VTree should contain Apple, got: '{}'", initial_text);
        assert!(initial_text.contains("Banana"), "Initial VTree should contain Banana, got: '{}'", initial_text);

        // 添加新列表项（通过替换整个数组触发 ref 响应式更新）
        let js_result = orchestrator.js_runtime().eval(
            "items = [...items, { id: 3, name: 'Cherry' }]"
        );
        assert!(js_result.is_ok(), "Failed to push item: {:?}", js_result);

        // 调用 render_frame 触发响应式更新
        orchestrator.last_frame_time = None;
        let rendered = orchestrator.render_frame();
        assert!(rendered, "render_frame should execute");

        // 验证 VTree 已更新包含新项
        let updated_vtree = orchestrator.vtree().expect("Updated VTree should be present");
        let updated_text = extract_vtree_text(&updated_vtree);
        assert!(updated_text.contains("Cherry"),
            "After push, VTree should contain Cherry, got: '{}'", updated_text);
        assert!(updated_text.contains("Apple"),
            "After push, VTree should still contain Apple, got: '{}'", updated_text);
        assert!(updated_text.contains("Banana"),
            "After push, VTree should still contain Banana, got: '{}'", updated_text);

        // 清理临时文件
        fs::remove_file(&temp_path).unwrap();
    }

    /// 辅助函数：从 VTree 中提取所有文本内容
    fn extract_vtree_text(vtree: &VTree) -> String {
        let mut texts = Vec::new();
        collect_texts(&vtree.root, &mut texts);
        texts.join(" ")
    }

    fn collect_texts(node: &iris_layout::vdom::VNode, texts: &mut Vec<String>) {
        match node {
            iris_layout::vdom::VNode::Element(elem) => {
                for child in &elem.children {
                    collect_texts(child, texts);
                }
            }
            iris_layout::vdom::VNode::Text(t) => {
                texts.push(t.clone());
            }
            _ => {}
        }
    }

    // ========== 端到端事件集成测试 (P0) ==========

    #[test]
    #[cfg(feature = "vue-sfc")]
    fn test_e2e_event_flow_click_handler() {
        use std::cell::RefCell;
        use std::rc::Rc;
        use iris_js::vue::{execute_render_function, inject_render_helpers};
        use iris_js::vm::JsRuntime;
        
        let mut orchestrator = RuntimeOrchestrator::new();
        
        // 1. 创建带 onClick 的 render 函数
        let render_code = r#"
function render() {
    return h('button', { onClick: function() { globalThis.clickHandled = true; } }, [
        text('Click me')
    ]);
}
"#;
        
        // 2. 执行 render 获取 VTree
        let result = execute_render_function(orchestrator.js_runtime(), render_code);
        assert!(result.is_ok(), "Render should succeed");
        
        let vtree = result.unwrap();
        orchestrator.vtree = Some(vtree);
        
        // 3. 转换为 DOMNode
        if let Some(ref vtree) = orchestrator.vtree {
            let dom_tree = vtree.to_dom_tree();
            orchestrator.dom_tree = Some(dom_tree);
        }
        
        // 4. 初始化事件系统
        orchestrator.event_dispatcher = iris_dom::event::EventDispatcher::new();
        
        // 5. 获取 button 节点的 _vnodeId
        let vnode_id = if let Some(ref vtree) = orchestrator.vtree {
            if let iris_layout::vdom::VNode::Element(elem) = &vtree.root {
                elem.attrs.get("_vnodeId").cloned().unwrap_or("1".to_string())
            } else {
                "1".to_string()
            }
        } else {
            "1".to_string()
        };
        
        let target_id: u64 = vnode_id.parse().unwrap_or(1);
        
        // 6. 模拟用户点击
        orchestrator.handle_mouse_click(target_id, 100.0, 100.0, 0);
        
        // 7. 处理事件队列
        orchestrator.process_pending_events();
        
        // 8. 验证 JS 侧 handler 被调用
        let handled = orchestrator.js_runtime()
            .eval("globalThis.clickHandled")
            .unwrap()
            .as_boolean()
            .unwrap_or(false);
        
        assert!(handled, "JS click handler should be invoked");
    }

    #[test]
    #[cfg(feature = "vue-sfc")]
    fn test_e2e_event_flow_with_event_types() {
        use iris_js::vue::{execute_render_function, inject_render_helpers};
        use iris_js::vm::JsRuntime;
        
        let mut orchestrator = RuntimeOrchestrator::new();
        
        // 创建带多个事件处理器的 render 函数
        let render_code = r#"
function render() {
    return h('input', { 
        onClick: function() { globalThis.clickCount = (globalThis.clickCount || 0) + 1; },
        onInput: function() { globalThis.inputCount = (globalThis.inputCount || 0) + 1; }
    }, [
        text('Input field')
    ]);
}
"#;
        
        // 执行 render
        let result = execute_render_function(orchestrator.js_runtime(), render_code);
        assert!(result.is_ok(), "Render should succeed");
        
        let vtree = result.unwrap();
        
        // 验证 VTree 中包含 _eventTypes
        if let iris_layout::vdom::VNode::Element(elem) = &vtree.root {
            assert!(elem.attrs.contains_key("_eventTypes"), 
                "VTree should contain _eventTypes attribute");
            
            let event_types_json = elem.attrs.get("_eventTypes").unwrap();
            assert!(event_types_json.contains("click"), 
                "_eventTypes should contain 'click'");
            assert!(event_types_json.contains("input"), 
                "_eventTypes should contain 'input'");
            
            assert!(elem.attrs.contains_key("_vnodeId"),
                "VTree should contain _vnodeId attribute");
        } else {
            panic!("Expected element node");
        }
        
        orchestrator.vtree = Some(vtree);
        
        // 转换为 DOMNode
        if let Some(ref vtree) = orchestrator.vtree {
            let dom_tree = vtree.to_dom_tree();
            orchestrator.dom_tree = Some(dom_tree);
        }
        
        // 验证事件冒泡系统能正确读取 _eventTypes
        if let Some(ref vtree) = orchestrator.vtree {
            let mut node_infos = std::collections::HashMap::new();
            RuntimeOrchestrator::collect_bubble_node_info(
                &vtree.root,
                "click",
                0,
                &mut node_infos,
            );
            
            // 应该至少有一个节点匹配 click 事件
            let matching_nodes: Vec<_> = node_infos.iter()
                .filter(|(_, (_, _, has_event))| *has_event)
                .collect();
            
            assert!(!matching_nodes.is_empty(), 
                "Should have at least one node with click event");
        }
    }
    
    // ==========================================
    // 事件冒泡机制测试
    // ==========================================
    
    #[test]
    fn test_hit_area_has_parent_id() {
        use super::hit_test::{HitIndex, HitArea};
        use iris_layout::dom::DOMNode;
        
        // 创建一个简单的 DOM 树
        let mut root = DOMNode::new_element("div".to_string());
        root.id = 1;
        root.parent_id = 0; // 根节点
        
        let mut child = DOMNode::new_element("button".to_string());
        child.id = 2;
        child.parent_id = 1; // 父节点是 root
        
        let mut grandchild = DOMNode::new_element("span".to_string());
        grandchild.id = 3;
        grandchild.parent_id = 2; // 父节点是 child
        
        root.children.push(child);
        root.children[0].children.push(grandchild);
        
        // 构建 HitIndex
        let mut hit_index = HitIndex::new();
        hit_index.rebuild(&root);
        
        // 验证 parent_id 正确设置
        let root_area = hit_index.get_area(1);
        assert!(root_area.is_some());
        assert_eq!(root_area.unwrap().parent_id, None); // 根节点无父节点
        
        let child_area = hit_index.get_area(2);
        assert!(child_area.is_some());
        assert_eq!(child_area.unwrap().parent_id, Some(1));
        
        let grandchild_area = hit_index.get_area(3);
        assert!(grandchild_area.is_some());
assert_eq!(grandchild_area.unwrap().parent_id, Some(2));
    }

// ============================================
// 事件委托单元测试
// ============================================

#[cfg(feature = "vue-sfc")]
#[test]
fn test_event_delegation_registration() {
    use super::RuntimeOrchestrator;
    
    let mut orchestrator = RuntimeOrchestrator::new();
    
    // 注册事件委托
    orchestrator.register_event_delegation(100, "button", "click");
    
    // 验证委托已注册
    assert!(orchestrator.event_delegations.contains_key(&100));
    assert_eq!(orchestrator.event_delegations[&100].len(), 1);
    assert_eq!(orchestrator.event_delegations[&100][0], ("button".to_string(), "click".to_string()));
}

#[cfg(feature = "vue-sfc")]
#[test]
fn test_event_delegation_multiple() {
    use super::RuntimeOrchestrator;
    
    let mut orchestrator = RuntimeOrchestrator::new();
    
    // 注册多个委托
    orchestrator.register_event_delegation(100, "button", "click");
    orchestrator.register_event_delegation(100, "li", "mouseover");
    orchestrator.register_event_delegation(200, "input", "change");
    
    // 验证
    assert_eq!(orchestrator.event_delegations[&100].len(), 2);
    assert_eq!(orchestrator.event_delegations[&200].len(), 1);
}

#[cfg(feature = "vue-sfc")]
#[test]
fn test_event_delegation_removal() {
    use super::RuntimeOrchestrator;
    
    let mut orchestrator = RuntimeOrchestrator::new();
    
    // 注册委托
    orchestrator.register_event_delegation(100, "button", "click");
    orchestrator.register_event_delegation(100, "li", "click");
    
    // 移除其中一个
    orchestrator.remove_event_delegation(100, "button", "click");
    
    // 验证
    assert_eq!(orchestrator.event_delegations[&100].len(), 1);
    assert_eq!(orchestrator.event_delegations[&100][0], ("li".to_string(), "click".to_string()));
}

#[cfg(feature = "vue-sfc")]
#[test]
fn test_selector_matching_tag() {
    use super::RuntimeOrchestrator;
    use iris_layout::dom::DOMNode;
    
    let mut orchestrator = RuntimeOrchestrator::new();
    
    // 创建一个 button 元素
    let button = DOMNode::new_element("button".to_string());
    
    // 构建 DOM 树
    orchestrator.dom_tree = Some(button);
    
    // 测试标签名匹配
    assert!(orchestrator.matches_delegation_selector(1, "button"));
    assert!(!orchestrator.matches_delegation_selector(1, "div"));
    assert!(!orchestrator.matches_delegation_selector(1, ".btn"));
}

#[cfg(feature = "vue-sfc")]
#[test]
fn test_selector_matching_class() {
    use super::RuntimeOrchestrator;
    use iris_layout::dom::DOMNode;
    
    let mut orchestrator = RuntimeOrchestrator::new();
    
    // 创建一个带 class 的 div 元素
    let mut div = DOMNode::new_element("div".to_string());
    
    // 设置 class 属性
    div.attributes.insert("class".to_string(), "btn btn-primary".to_string());
    
    orchestrator.dom_tree = Some(div);
    
    // 测试 class 匹配
    assert!(orchestrator.matches_delegation_selector(1, ".btn"));
    assert!(orchestrator.matches_delegation_selector(1, ".btn-primary"));
    assert!(!orchestrator.matches_delegation_selector(1, ".btn-secondary"));
    assert!(!orchestrator.matches_delegation_selector(1, "div"));
}

#[cfg(feature = "vue-sfc")]
#[test]
fn test_selector_matching_id() {
    use super::RuntimeOrchestrator;
    use iris_layout::dom::DOMNode;
    
    let mut orchestrator = RuntimeOrchestrator::new();
    
    // 创建一个带 id 的 input 元素
    let mut input = DOMNode::new_element("input".to_string());
    
    // 设置 id 属性
    input.attributes.insert("id".to_string(), "submit-btn".to_string());
    
    orchestrator.dom_tree = Some(input);
    
    // 测试 ID 匹配
    assert!(orchestrator.matches_delegation_selector(1, "#submit-btn"));
    assert!(!orchestrator.matches_delegation_selector(1, "#cancel-btn"));
    assert!(!orchestrator.matches_delegation_selector(1, "input"));
}

#[cfg(feature = "vue-sfc")]
#[test]
fn test_stop_propagation_flag_detection() {
    use super::RuntimeOrchestrator;
    
    let mut orchestrator = RuntimeOrchestrator::new();
    
    // 测试 1: 设置全局变量为 true
    let _ = orchestrator.js_runtime.eval("globalThis.__iris_lastEventPropagationStopped = true");
    assert!(orchestrator.check_stop_propagation());
    
    // 测试 2: 全局变量已被清理，应该返回 false
    assert!(!orchestrator.check_stop_propagation());
    
    // 测试 3: 设置全局变量为 false
    let _ = orchestrator.js_runtime.eval("globalThis.__iris_lastEventPropagationStopped = false");
    assert!(!orchestrator.check_stop_propagation());
    
    // 测试 4: 全局变量不存在，应该返回 false
    assert!(!orchestrator.check_stop_propagation());
}

#[cfg(feature = "vue-sfc")]
#[test]
fn test_selector_matching_descendant() {
    use super::RuntimeOrchestrator;
    use iris_layout::dom::DOMNode;
    
    let mut orchestrator = RuntimeOrchestrator::new();
    
    // 创建 DOM 树: ul > li > span
    let mut span = DOMNode::new_element("span".to_string());
    span.id = 3;
    
    let mut li = DOMNode::new_element("li".to_string());
    li.id = 2;
    li.children.push(span);
    li.children[0].parent_id = 2;
    
    let mut ul = DOMNode::new_element("ul".to_string());
    ul.id = 1;
    ul.children.push(li);
    ul.children[0].parent_id = 1;
    
    orchestrator.dom_tree = Some(ul);
    
    // 测试后代选择器: "ul li" 应该匹配 <li>
    assert!(orchestrator.matches_delegation_selector(2, "ul li"));
    
    // 测试后代选择器: "ul span" 应该匹配 <span>
    assert!(orchestrator.matches_delegation_selector(3, "ul span"));
    
    // 测试后代选择器: "li span" 应该匹配 <span>
    assert!(orchestrator.matches_delegation_selector(3, "li span"));
    
    // 测试不匹配: "div li" 不应该匹配
    assert!(!orchestrator.matches_delegation_selector(2, "div li"));
}

#[cfg(feature = "vue-sfc")]
#[test]
fn test_selector_matching_child() {
    use super::RuntimeOrchestrator;
    use iris_layout::dom::DOMNode;
    
    let mut orchestrator = RuntimeOrchestrator::new();
    
    // 创建 DOM 树: ul > li > span
    let mut span = DOMNode::new_element("span".to_string());
    span.id = 3;
    
    let mut li = DOMNode::new_element("li".to_string());
    li.id = 2;
    li.children.push(span);
    li.children[0].parent_id = 2;
    
    let mut ul = DOMNode::new_element("ul".to_string());
    ul.id = 1;
    ul.children.push(li);
    ul.children[0].parent_id = 1;
    
    orchestrator.dom_tree = Some(ul);
    
    // 测试子选择器: "ul > li" 应该匹配 <li>
    assert!(orchestrator.matches_delegation_selector(2, "ul > li"));
    
    // 测试子选择器: "li > span" 应该匹配 <span>
    assert!(orchestrator.matches_delegation_selector(3, "li > span"));
    
    // 测试子选择器: "ul > span" 不应该匹配 (span 不是 ul 的直接子元素)
    assert!(!orchestrator.matches_delegation_selector(3, "ul > span"));
}

#[cfg(feature = "vue-sfc")]
#[test]
fn test_selector_matching_multiple_classes() {
    use super::RuntimeOrchestrator;
    use iris_layout::dom::DOMNode;
    
    let mut orchestrator = RuntimeOrchestrator::new();
    
    // 创建一个带多个 class 的 button
    let mut button = DOMNode::new_element("button".to_string());
    button.attributes.insert("class".to_string(), "btn btn-primary active".to_string());
    
    orchestrator.dom_tree = Some(button);
    
    // 测试多 Class 选择器
    assert!(orchestrator.matches_delegation_selector(1, ".btn.btn-primary"));
    assert!(orchestrator.matches_delegation_selector(1, ".btn.active"));
    assert!(orchestrator.matches_delegation_selector(1, ".btn-primary.active"));
    assert!(orchestrator.matches_delegation_selector(1, ".btn.btn-primary.active"));
    
    // 测试不匹配
    assert!(!orchestrator.matches_delegation_selector(1, ".btn.btn-secondary"));
    assert!(!orchestrator.matches_delegation_selector(1, ".disabled"));
}