11
11
//! # Examples
12
12
//!
13
13
//! ```rust
14
+ //! use tauri::test::{mock_builder, mock_context, noop_assets};
15
+ //!
14
16
//! #[tauri::command]
15
- //! fn my_cmd() {}
17
+ //! fn ping() -> &'static str {
18
+ //! "pong"
19
+ //! }
16
20
//!
17
- //! fn create_app<R: tauri::Runtime>(mut builder: tauri::Builder<R>) -> tauri::App<R> {
18
- //! builder
19
- //! .setup(|app| {
20
- //! // do something
21
- //! Ok(())
22
- //! })
23
- //! .invoke_handler(tauri::generate_handler![my_cmd])
24
- //! // remove the string argument on your app
25
- //! .build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
26
- //! .expect("failed to build app")
21
+ //! fn create_app<R: tauri::Runtime>(builder: tauri::Builder<R>) -> tauri::App<R> {
22
+ //! builder
23
+ //! .invoke_handler(tauri::generate_handler![ping])
24
+ //! // remove the string argument to use your app's config file
25
+ //! .build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
26
+ //! .expect("failed to build app")
27
27
//! }
28
28
//!
29
29
//! fn main() {
30
- //! // let app = create_app(tauri::Builder::default());
31
- //! // app.run(|_handle, _event| {});
32
- //! }
30
+ //! let app = create_app(mock_builder());
31
+ //! let window = tauri::WindowBuilder::new(&app, "main", Default::default())
32
+ //! .build()
33
+ //! .unwrap();
33
34
//!
34
- //! //#[cfg(test)]
35
- //! mod tests {
36
- //! use tauri::Manager;
37
- //! //#[cfg(test)]
38
- //! fn something() {
39
- //! let app = super::create_app(tauri::test::mock_builder());
40
- //! let window = app.get_window("main").unwrap();
41
- //! // do something with the app and window
42
- //! // in this case we'll run the my_cmd command with no arguments
43
- //! tauri::test::assert_ipc_response(
44
- //! &window,
45
- //! tauri::window::InvokeRequest {
46
- //! cmd: "my_cmd".into(),
47
- //! callback: tauri::ipc::CallbackFn(0),
48
- //! error: tauri::ipc::CallbackFn(1),
49
- //! body: serde_json::Value::Null.into(),
50
- //! headers: Default::default(),
51
- //! },
52
- //! Ok(())
53
- //! );
54
- //! }
35
+ //! // run the `ping` command and assert it returns `pong`
36
+ //! let res = tauri::test::get_ipc_response(
37
+ //! &window,
38
+ //! tauri::window::InvokeRequest {
39
+ //! cmd: "ping".into(),
40
+ //! callback: tauri::ipc::CallbackFn(0),
41
+ //! error: tauri::ipc::CallbackFn(1),
42
+ //! body: tauri::ipc::InvokeBody::default(),
43
+ //! headers: Default::default(),
44
+ //! },
45
+ //! ).map(|b| b.deserialize::<String>().unwrap());
55
46
//! }
56
47
//! ```
57
48
@@ -61,14 +52,10 @@ mod mock_runtime;
61
52
pub use mock_runtime:: * ;
62
53
use serde:: Serialize ;
63
54
64
- use std:: {
65
- borrow:: Cow ,
66
- fmt:: Debug ,
67
- hash:: { Hash , Hasher } ,
68
- } ;
55
+ use std:: { borrow:: Cow , fmt:: Debug } ;
69
56
70
57
use crate :: {
71
- ipc:: { CallbackFn , InvokeResponse } ,
58
+ ipc:: { InvokeBody , InvokeError , InvokeResponse } ,
72
59
window:: InvokeRequest ,
73
60
App , Builder , Context , Pattern , Window ,
74
61
} ;
@@ -77,19 +64,6 @@ use tauri_utils::{
77
64
config:: { Config , PatternKind , TauriConfig } ,
78
65
} ;
79
66
80
- #[ derive( Eq , PartialEq ) ]
81
- struct IpcKey {
82
- callback : CallbackFn ,
83
- error : CallbackFn ,
84
- }
85
-
86
- impl Hash for IpcKey {
87
- fn hash < H : Hasher > ( & self , state : & mut H ) {
88
- self . callback . 0 . hash ( state) ;
89
- self . error . 0 . hash ( state) ;
90
- }
91
- }
92
-
93
67
/// An empty [`Assets`] implementation.
94
68
pub struct NoopAsset {
95
69
csp_hashes : Vec < CspHash < ' static > > ,
@@ -175,74 +149,114 @@ pub fn mock_app() -> App<MockRuntime> {
175
149
/// # Examples
176
150
///
177
151
/// ```rust
152
+ /// use tauri::test::{mock_builder, mock_context, noop_assets};
153
+ ///
178
154
/// #[tauri::command]
179
155
/// fn ping() -> &'static str {
180
- /// "pong"
156
+ /// "pong"
181
157
/// }
182
158
///
183
- /// fn create_app<R: tauri::Runtime>(mut builder: tauri::Builder<R>) -> tauri::App<R> {
184
- /// builder
185
- /// .invoke_handler(tauri::generate_handler![ping])
186
- /// // remove the string argument on your app
187
- /// .build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
188
- /// .expect("failed to build app")
159
+ /// fn create_app<R: tauri::Runtime>(builder: tauri::Builder<R>) -> tauri::App<R> {
160
+ /// builder
161
+ /// .invoke_handler(tauri::generate_handler![ping])
162
+ /// // remove the string argument to use your app's config file
163
+ /// .build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
164
+ /// .expect("failed to build app")
189
165
/// }
190
166
///
191
167
/// fn main() {
192
- /// // let app = create_app(tauri::Builder::default());
193
- /// // app.run(|_handle, _event| {});}
194
- /// }
195
- ///
196
- /// //#[cfg(test)]
197
- /// mod tests {
198
- /// use tauri::Manager;
199
- ///
200
- /// //#[cfg(test)]
201
- /// fn something() {
202
- /// let app = super::create_app(tauri::test::mock_builder());
203
- /// let window = app.get_window("main").unwrap();
168
+ /// let app = create_app(mock_builder());
169
+ /// let window = tauri::WindowBuilder::new(&app, "main", Default::default())
170
+ /// .build()
171
+ /// .unwrap();
204
172
///
205
173
/// // run the `ping` command and assert it returns `pong`
206
174
/// tauri::test::assert_ipc_response(
207
- /// &window,
208
- /// tauri::window::InvokeRequest {
209
- /// cmd: "ping".into(),
210
- /// callback: tauri::ipc::CallbackFn(0),
211
- /// error: tauri::ipc::CallbackFn(1),
212
- /// body: serde_json::Value::Null.into(),
213
- /// headers: Default::default(),
214
- /// },
215
- /// // the expected response is a success with the "pong" payload
216
- /// // we could also use Err("error message") here to ensure the command failed
175
+ /// &window,
176
+ /// tauri::window::InvokeRequest {
177
+ /// cmd: "ping".into(),
178
+ /// callback: tauri::ipc::CallbackFn(0),
179
+ /// error: tauri::ipc::CallbackFn(1),
180
+ /// body: tauri::ipc::InvokeBody::default(),
181
+ /// headers: Default::default(),
182
+ /// },
217
183
/// Ok("pong")
218
184
/// );
219
- /// }
220
185
/// }
221
186
/// ```
222
187
pub fn assert_ipc_response < T : Serialize + Debug + Send + Sync + ' static > (
223
188
window : & Window < MockRuntime > ,
224
189
request : InvokeRequest ,
225
190
expected : Result < T , T > ,
226
191
) {
192
+ let response =
193
+ get_ipc_response ( window, request) . map ( |b| b. deserialize :: < serde_json:: Value > ( ) . unwrap ( ) ) ;
194
+ assert_eq ! (
195
+ response,
196
+ expected
197
+ . map( |e| serde_json:: to_value( e) . unwrap( ) )
198
+ . map_err( |e| serde_json:: to_value( e) . unwrap( ) )
199
+ ) ;
200
+ }
201
+
202
+ /// Executes the given IPC message and get the return value.
203
+ ///
204
+ /// # Examples
205
+ ///
206
+ /// ```rust
207
+ /// use tauri::test::{mock_builder, mock_context, noop_assets};
208
+ ///
209
+ /// #[tauri::command]
210
+ /// fn ping() -> &'static str {
211
+ /// "pong"
212
+ /// }
213
+ ///
214
+ /// fn create_app<R: tauri::Runtime>(builder: tauri::Builder<R>) -> tauri::App<R> {
215
+ /// builder
216
+ /// .invoke_handler(tauri::generate_handler![ping])
217
+ /// // remove the string argument to use your app's config file
218
+ /// .build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
219
+ /// .expect("failed to build app")
220
+ /// }
221
+ ///
222
+ /// fn main() {
223
+ /// let app = create_app(mock_builder());
224
+ /// let window = tauri::WindowBuilder::new(&app, "main", Default::default())
225
+ /// .build()
226
+ /// .unwrap();
227
+ ///
228
+ /// // run the `ping` command and assert it returns `pong`
229
+ /// let res = tauri::test::get_ipc_response(
230
+ /// &window,
231
+ /// tauri::window::InvokeRequest {
232
+ /// cmd: "ping".into(),
233
+ /// callback: tauri::ipc::CallbackFn(0),
234
+ /// error: tauri::ipc::CallbackFn(1),
235
+ /// body: tauri::ipc::InvokeBody::default(),
236
+ /// headers: Default::default(),
237
+ /// },
238
+ /// );
239
+ /// assert!(res.is_ok());
240
+ /// assert_eq!(res.unwrap().deserialize::<String>().unwrap(), String::from("pong"));
241
+ /// }
242
+ ///```
243
+ pub fn get_ipc_response (
244
+ window : & Window < MockRuntime > ,
245
+ request : InvokeRequest ,
246
+ ) -> Result < InvokeBody , serde_json:: Value > {
227
247
let ( tx, rx) = std:: sync:: mpsc:: sync_channel ( 1 ) ;
228
248
window. clone ( ) . on_message (
229
249
request,
230
250
Box :: new ( move |_window, _cmd, response, _callback, _error| {
231
- assert_eq ! (
232
- match response {
233
- InvokeResponse :: Ok ( b) => Ok ( b. into_json( ) ) ,
234
- InvokeResponse :: Err ( e) => Err ( e. 0 ) ,
235
- } ,
236
- expected
237
- . map( |e| serde_json:: to_value( e) . unwrap( ) )
238
- . map_err( |e| serde_json:: to_value( e) . unwrap( ) )
239
- ) ;
240
-
241
- tx. send ( ( ) ) . unwrap ( ) ;
251
+ tx. send ( response) . unwrap ( ) ;
242
252
} ) ,
243
253
) ;
244
254
245
- rx. recv ( ) . unwrap ( ) ;
255
+ let res = rx. recv ( ) . expect ( "Failed to receive result from command" ) ;
256
+ match res {
257
+ InvokeResponse :: Ok ( b) => Ok ( b) ,
258
+ InvokeResponse :: Err ( InvokeError ( v) ) => Err ( v) ,
259
+ }
246
260
}
247
261
248
262
#[ cfg( test) ]
0 commit comments