1use crate::tests::TestServer;
2use gpui::{executor::Deterministic, TestAppContext};
3use rpc::Notification;
4use std::sync::Arc;
5
6#[gpui::test]
7async fn test_notifications(
8 deterministic: Arc<Deterministic>,
9 cx_a: &mut TestAppContext,
10 cx_b: &mut TestAppContext,
11) {
12 deterministic.forbid_parking();
13 let mut server = TestServer::start(&deterministic).await;
14 let client_a = server.create_client(cx_a, "user_a").await;
15 let client_b = server.create_client(cx_b, "user_b").await;
16
17 // Client A sends a contact request to client B.
18 client_a
19 .user_store()
20 .update(cx_a, |store, cx| store.request_contact(client_b.id(), cx))
21 .await
22 .unwrap();
23
24 // Client B receives a contact request notification and responds to the
25 // request, accepting it.
26 deterministic.run_until_parked();
27 client_b.notification_store().update(cx_b, |store, cx| {
28 assert_eq!(store.notification_count(), 1);
29 assert_eq!(store.unread_notification_count(), 1);
30
31 let entry = store.notification_at(0).unwrap();
32 assert_eq!(
33 entry.notification,
34 Notification::ContactRequest {
35 sender_id: client_a.id()
36 }
37 );
38 assert!(!entry.is_read);
39
40 store.respond_to_notification(entry.notification.clone(), true, cx);
41 });
42
43 // Client B sees the notification is now read, and that they responded.
44 deterministic.run_until_parked();
45 client_b.notification_store().read_with(cx_b, |store, _| {
46 assert_eq!(store.notification_count(), 1);
47 assert_eq!(store.unread_notification_count(), 0);
48
49 let entry = store.notification_at(0).unwrap();
50 assert!(entry.is_read);
51 assert_eq!(entry.response, Some(true));
52 });
53
54 // Client A receives a notification that client B accepted their request.
55 client_a.notification_store().read_with(cx_a, |store, _| {
56 assert_eq!(store.notification_count(), 1);
57 assert_eq!(store.unread_notification_count(), 1);
58
59 let entry = store.notification_at(0).unwrap();
60 assert_eq!(
61 entry.notification,
62 Notification::ContactRequestAccepted {
63 responder_id: client_b.id()
64 }
65 );
66 assert!(!entry.is_read);
67 });
68
69 // Client A creates a channel and invites client B to be a member.
70 let channel_id = client_a
71 .channel_store()
72 .update(cx_a, |store, cx| {
73 store.create_channel("the-channel", None, cx)
74 })
75 .await
76 .unwrap();
77 client_a
78 .channel_store()
79 .update(cx_a, |store, cx| {
80 store.invite_member(channel_id, client_b.id(), false, cx)
81 })
82 .await
83 .unwrap();
84
85 // Client B receives a channel invitation notification and responds to the
86 // invitation, accepting it.
87 deterministic.run_until_parked();
88 client_b.notification_store().update(cx_b, |store, cx| {
89 assert_eq!(store.notification_count(), 2);
90 assert_eq!(store.unread_notification_count(), 1);
91
92 let entry = store.notification_at(1).unwrap();
93 assert_eq!(
94 entry.notification,
95 Notification::ChannelInvitation {
96 channel_id,
97 channel_name: "the-channel".to_string()
98 }
99 );
100 assert!(!entry.is_read);
101
102 store.respond_to_notification(entry.notification.clone(), true, cx);
103 });
104
105 // Client B sees the notification is now read, and that they responded.
106 deterministic.run_until_parked();
107 client_b.notification_store().read_with(cx_b, |store, _| {
108 assert_eq!(store.notification_count(), 2);
109 assert_eq!(store.unread_notification_count(), 0);
110
111 let entry = store.notification_at(1).unwrap();
112 assert!(entry.is_read);
113 assert_eq!(entry.response, Some(true));
114 });
115}