1use std::{
2 future::Future,
3 path::PathBuf,
4};
5
6use accesskit::{
7 Node,
8 Role,
9};
10use dioxus_core::{
11 fc_to_builder,
12 Element,
13 IntoDynNode,
14 VirtualDom,
15};
16use dioxus_core_macro::{
17 component,
18 rsx,
19 Props,
20};
21#[cfg(debug_assertions)]
22use dioxus_signals::{
23 GlobalSignal,
24 Readable,
25};
26use freya_components::NativeContainer;
27use freya_core::{
28 accessibility::{
29 AccessibilityTree,
30 ACCESSIBILITY_ROOT_ID,
31 },
32 dom::{
33 FreyaDOM,
34 SafeDOM,
35 },
36 event_loop_messages::EventLoopMessage,
37 events::NodesState,
38 platform::CursorIcon,
39 platform_state::{
40 NativePlatformState,
41 NavigationMode,
42 PlatformInformation,
43 PreferredTheme,
44 },
45 types::EventsQueue,
46};
47use freya_elements as dioxus_elements;
48use freya_engine::prelude::*;
49use tokio::{
50 runtime::Runtime,
51 sync::{
52 broadcast,
53 mpsc::unbounded_channel,
54 watch,
55 },
56};
57use torin::prelude::Size2D;
58
59use crate::{
60 config::TestingConfig,
61 test_handler::TestingHandler,
62 test_utils::TestUtils,
63 SCALE_FACTOR,
64};
65
66pub fn launch_test(root: AppComponent) -> TestingHandler<()> {
98 launch_test_with_config(root, TestingConfig::default())
99}
100
101pub fn launch_test_with_config<T: 'static + Clone>(
103 root: AppComponent,
104 config: TestingConfig<T>,
105) -> TestingHandler<T> {
106 let vdom = with_accessibility(root);
107 let fdom = FreyaDOM::default();
108 let sdom = SafeDOM::new(fdom);
109
110 let (event_emitter, event_receiver) = unbounded_channel();
111 let (platform_event_emitter, platform_event_receiver) = unbounded_channel::<EventLoopMessage>();
112 let (platform_sender, platform_receiver) = watch::channel(NativePlatformState {
113 focused_accessibility_id: ACCESSIBILITY_ROOT_ID,
114 focused_accessibility_node: Node::new(Role::Window),
115 preferred_theme: PreferredTheme::default(),
116 navigation_mode: NavigationMode::default(),
117 information: PlatformInformation::new(config.size, false, false, false),
118 scale_factor: SCALE_FACTOR,
119 });
120 let mut font_collection = FontCollection::new();
121 let font_mgr = FontMgr::default();
122 font_collection.set_dynamic_font_manager(font_mgr.clone());
123 font_collection.set_default_font_manager(font_mgr.clone(), None);
124
125 let mut handler = TestingHandler {
126 vdom,
127 events_queue: EventsQueue::new(),
128 nodes_state: NodesState::default(),
129 font_collection,
130 font_mgr,
131 event_emitter,
132 event_receiver,
133 utils: TestUtils { sdom },
134 config,
135 platform_event_emitter,
136 platform_event_receiver,
137 accessibility_tree: AccessibilityTree::new(ACCESSIBILITY_ROOT_ID),
138 ticker_sender: broadcast::channel(5).0,
139 cursor_icon: CursorIcon::default(),
140 platform_sender,
141 platform_receiver,
142 };
143
144 handler.init_doms();
145 handler.resize(handler.config.size);
146
147 handler
148}
149
150fn with_accessibility(app: AppComponent) -> VirtualDom {
151 #[derive(Clone)]
152 struct RootProps {
153 app: AppComponent,
154 }
155
156 #[allow(non_snake_case)]
157 fn Root(props: RootProps) -> Element {
158 #[allow(non_snake_case)]
159 let App = props.app;
160
161 rsx!(NativeContainer {
162 App {}
163 })
164 }
165
166 VirtualDom::new_with_props(Root, RootProps { app })
167}
168
169type AppComponent = fn() -> Element;
170
171#[component]
172pub fn Preview(children: Element) -> Element {
173 rsx!(
174 rect {
175 main_align: "center",
176 cross_align: "center",
177 width: "fill",
178 height: "fill",
179 spacing: "8",
180 {children}
181 }
182 )
183}
184
185pub fn launch_doc(root: AppComponent, size: Size2D, path: impl Into<PathBuf>) {
186 let path: PathBuf = path.into();
187 launch_doc_with_utils(root, size, move |mut utils| async move {
188 utils.wait_for_update().await;
189 utils.save_snapshot(&path);
190 });
191}
192
193pub fn launch_doc_with_utils<F: Future<Output = ()>>(
194 root: AppComponent,
195 size: Size2D,
196 cb: impl FnOnce(TestingHandler<()>) -> F,
197) {
198 let mut utils = launch_test(root);
199 utils.resize(size);
200 let rt = Runtime::new().unwrap();
201 rt.block_on(async move {
202 cb(utils).await;
203 });
204}