Skip to main content

max / goingson

8.6 KB · 288 lines History Blame Raw
1 //! Integration tests for email repository operations.
2 //!
3 //! Tests local SQLite email operations only (no IMAP/SMTP).
4
5 use chrono::{Duration, Utc};
6 use goingson_core::NewEmail;
7
8 use crate::test_utils::{create_test_project, setup_test_state};
9
10 #[tokio::test]
11 async fn create_and_list_email() {
12 let (state, user_id) = setup_test_state().await;
13
14 let new_email = NewEmail {
15 project_id: None,
16 from_address: "sender@example.com".to_string(),
17 to_address: "me@example.com".to_string(),
18 subject: "Test Subject".to_string(),
19 body: "Test body content".to_string(),
20 is_read: false,
21 received_at: Some(Utc::now()),
22 };
23
24 let email = state.emails.create(user_id, new_email).await.unwrap();
25 assert_eq!(email.subject, "Test Subject");
26 assert_eq!(email.from, "sender@example.com");
27
28 // List should include the email
29 let emails = state.emails.list_all(user_id, false).await.unwrap();
30 assert_eq!(emails.len(), 1);
31 assert_eq!(emails[0].subject, "Test Subject");
32 }
33
34 #[tokio::test]
35 async fn mark_email_read_unread() {
36 let (state, user_id) = setup_test_state().await;
37
38 let new_email = NewEmail {
39 project_id: None,
40 from_address: "sender@example.com".to_string(),
41 to_address: "me@example.com".to_string(),
42 subject: "Read/Unread Test".to_string(),
43 body: "Body".to_string(),
44 is_read: false,
45 received_at: Some(Utc::now()),
46 };
47
48 let email = state.emails.create(user_id, new_email).await.unwrap();
49 assert!(!email.is_read);
50
51 // Mark as read
52 let read_result = state.emails.mark_read(email.id, user_id).await.unwrap();
53 assert!(read_result);
54
55 // Verify it's read
56 let fetched = state.emails.get_by_id(email.id, user_id).await.unwrap().unwrap();
57 assert!(fetched.is_read);
58
59 // Mark as unread
60 let unread_result = state.emails.mark_unread(email.id, user_id).await.unwrap();
61 assert!(unread_result);
62
63 // Verify it's unread
64 let fetched = state.emails.get_by_id(email.id, user_id).await.unwrap().unwrap();
65 assert!(!fetched.is_read);
66 }
67
68 #[tokio::test]
69 async fn snooze_and_unsnooze_email() {
70 let (state, user_id) = setup_test_state().await;
71
72 let new_email = NewEmail {
73 project_id: None,
74 from_address: "sender@example.com".to_string(),
75 to_address: "me@example.com".to_string(),
76 subject: "Snooze Test".to_string(),
77 body: "Body".to_string(),
78 is_read: false,
79 received_at: Some(Utc::now()),
80 };
81
82 let email = state.emails.create(user_id, new_email).await.unwrap();
83
84 // Snooze until future date
85 let snooze_until = Utc::now() + Duration::days(3);
86 let snoozed = state
87 .emails
88 .snooze(email.id, user_id, snooze_until)
89 .await
90 .unwrap()
91 .unwrap();
92 assert!(snoozed.snoozed_until.is_some());
93
94 // Verify it appears in snoozed list
95 let snoozed_list = state.emails.list_snoozed(user_id).await.unwrap();
96 assert_eq!(snoozed_list.len(), 1);
97 assert_eq!(snoozed_list[0].id, email.id);
98
99 // Unsnooze
100 let unsnoozed = state
101 .emails
102 .unsnooze(email.id, user_id)
103 .await
104 .unwrap()
105 .unwrap();
106 assert!(unsnoozed.snoozed_until.is_none());
107
108 // Verify snoozed list is empty
109 let snoozed_list = state.emails.list_snoozed(user_id).await.unwrap();
110 assert!(snoozed_list.is_empty());
111 }
112
113 #[tokio::test]
114 async fn mark_waiting_and_clear() {
115 let (state, user_id) = setup_test_state().await;
116
117 let new_email = NewEmail {
118 project_id: None,
119 from_address: "sender@example.com".to_string(),
120 to_address: "me@example.com".to_string(),
121 subject: "Waiting Test".to_string(),
122 body: "Body".to_string(),
123 is_read: false,
124 received_at: Some(Utc::now()),
125 };
126
127 let email = state.emails.create(user_id, new_email).await.unwrap();
128
129 // Mark as waiting
130 let expected_date = Utc::now() + Duration::days(5);
131 let waiting = state
132 .emails
133 .mark_waiting(email.id, user_id, Some(expected_date))
134 .await
135 .unwrap()
136 .unwrap();
137 assert!(waiting.is_waiting());
138
139 // Verify it appears in waiting list
140 let waiting_list = state.emails.list_waiting(user_id).await.unwrap();
141 assert_eq!(waiting_list.len(), 1);
142
143 // Clear waiting
144 let cleared = state
145 .emails
146 .clear_waiting(email.id, user_id)
147 .await
148 .unwrap()
149 .unwrap();
150 assert!(!cleared.is_waiting());
151
152 // Verify waiting list is empty
153 let waiting_list = state.emails.list_waiting(user_id).await.unwrap();
154 assert!(waiting_list.is_empty());
155 }
156
157 #[tokio::test]
158 async fn archive_email_local() {
159 let (state, user_id) = setup_test_state().await;
160
161 let new_email = NewEmail {
162 project_id: None,
163 from_address: "sender@example.com".to_string(),
164 to_address: "me@example.com".to_string(),
165 subject: "Archive Test".to_string(),
166 body: "Body".to_string(),
167 is_read: false,
168 received_at: Some(Utc::now()),
169 };
170
171 let email = state.emails.create(user_id, new_email).await.unwrap();
172
173 // Archive
174 let archived = state.emails.archive(email.id, user_id).await.unwrap();
175 assert!(archived);
176
177 // Not in normal list (exclude archived)
178 let emails = state.emails.list_all(user_id, false).await.unwrap();
179 assert!(emails.is_empty());
180
181 // In list when including archived
182 let all_emails = state.emails.list_all(user_id, true).await.unwrap();
183 assert_eq!(all_emails.len(), 1);
184 }
185
186 #[tokio::test]
187 async fn link_email_to_project() {
188 let (state, user_id) = setup_test_state().await;
189 let project_id = create_test_project(&state, user_id).await;
190
191 let new_email = NewEmail {
192 project_id: None,
193 from_address: "sender@example.com".to_string(),
194 to_address: "me@example.com".to_string(),
195 subject: "Link Test".to_string(),
196 body: "Body".to_string(),
197 is_read: false,
198 received_at: Some(Utc::now()),
199 };
200
201 let email = state.emails.create(user_id, new_email).await.unwrap();
202 assert!(email.project_id.is_none());
203
204 // Link to project
205 let linked = state
206 .emails
207 .link_to_project(email.id, user_id, Some(project_id))
208 .await
209 .unwrap();
210 assert!(linked);
211
212 // Verify in project emails
213 let project_emails = state
214 .emails
215 .list_by_project(user_id, project_id)
216 .await
217 .unwrap();
218 assert_eq!(project_emails.len(), 1);
219 assert_eq!(project_emails[0].id, email.id);
220 }
221
222 #[tokio::test]
223 async fn list_unlinked_emails() {
224 let (state, user_id) = setup_test_state().await;
225 let project_id = create_test_project(&state, user_id).await;
226
227 // Create a linked email
228 let linked_email = NewEmail {
229 project_id: Some(project_id),
230 from_address: "linked@example.com".to_string(),
231 to_address: "me@example.com".to_string(),
232 subject: "Linked Email".to_string(),
233 body: "Body".to_string(),
234 is_read: false,
235 received_at: Some(Utc::now()),
236 };
237 state.emails.create(user_id, linked_email).await.unwrap();
238
239 // Create an unlinked email
240 let unlinked_email = NewEmail {
241 project_id: None,
242 from_address: "unlinked@example.com".to_string(),
243 to_address: "me@example.com".to_string(),
244 subject: "Unlinked Email".to_string(),
245 body: "Body".to_string(),
246 is_read: false,
247 received_at: Some(Utc::now()),
248 };
249 state.emails.create(user_id, unlinked_email).await.unwrap();
250
251 let unlinked = state.emails.list_unlinked(user_id).await.unwrap();
252 assert_eq!(unlinked.len(), 1);
253 assert_eq!(unlinked[0].subject, "Unlinked Email");
254 }
255
256 #[tokio::test]
257 async fn count_unread() {
258 let (state, user_id) = setup_test_state().await;
259
260 // Initially zero
261 let count = state.emails.count_unread(user_id).await.unwrap();
262 assert_eq!(count, 0);
263
264 // Create two unread emails
265 for i in 0..2 {
266 let new_email = NewEmail {
267 project_id: None,
268 from_address: format!("sender{}@example.com", i),
269 to_address: "me@example.com".to_string(),
270 subject: format!("Email {}", i),
271 body: "Body".to_string(),
272 is_read: false,
273 received_at: Some(Utc::now()),
274 };
275 state.emails.create(user_id, new_email).await.unwrap();
276 }
277
278 let count = state.emails.count_unread(user_id).await.unwrap();
279 assert_eq!(count, 2);
280
281 // Mark one as read
282 let emails = state.emails.list_all(user_id, false).await.unwrap();
283 state.emails.mark_read(emails[0].id, user_id).await.unwrap();
284
285 let count = state.emails.count_unread(user_id).await.unwrap();
286 assert_eq!(count, 1);
287 }
288