notification_tests.rs

  1use crate::tests::TestServer;
  2use gpui::{executor::Deterministic, TestAppContext};
  3use notifications::NotificationEvent;
  4use parking_lot::Mutex;
  5use rpc::{proto, Notification};
  6use std::sync::Arc;
  7
  8#[gpui::test]
  9async fn test_notifications(
 10    deterministic: Arc<Deterministic>,
 11    cx_a: &mut TestAppContext,
 12    cx_b: &mut TestAppContext,
 13) {
 14    deterministic.forbid_parking();
 15    let mut server = TestServer::start(&deterministic).await;
 16    let client_a = server.create_client(cx_a, "user_a").await;
 17    let client_b = server.create_client(cx_b, "user_b").await;
 18
 19    let notification_events_a = Arc::new(Mutex::new(Vec::new()));
 20    let notification_events_b = Arc::new(Mutex::new(Vec::new()));
 21    client_a.notification_store().update(cx_a, |_, cx| {
 22        let events = notification_events_a.clone();
 23        cx.subscribe(&cx.handle(), move |_, _, event, _| {
 24            events.lock().push(event.clone());
 25        })
 26        .detach()
 27    });
 28    client_b.notification_store().update(cx_b, |_, cx| {
 29        let events = notification_events_b.clone();
 30        cx.subscribe(&cx.handle(), move |_, _, event, _| {
 31            events.lock().push(event.clone());
 32        })
 33        .detach()
 34    });
 35
 36    // Client A sends a contact request to client B.
 37    client_a
 38        .user_store()
 39        .update(cx_a, |store, cx| store.request_contact(client_b.id(), cx))
 40        .await
 41        .unwrap();
 42
 43    // Client B receives a contact request notification and responds to the
 44    // request, accepting it.
 45    deterministic.run_until_parked();
 46    client_b.notification_store().update(cx_b, |store, cx| {
 47        assert_eq!(store.notification_count(), 1);
 48        assert_eq!(store.unread_notification_count(), 1);
 49
 50        let entry = store.notification_at(0).unwrap();
 51        assert_eq!(
 52            entry.notification,
 53            Notification::ContactRequest {
 54                sender_id: client_a.id()
 55            }
 56        );
 57        assert!(!entry.is_read);
 58        assert_eq!(
 59            &notification_events_b.lock()[0..],
 60            &[
 61                NotificationEvent::NewNotification {
 62                    entry: entry.clone(),
 63                },
 64                NotificationEvent::NotificationsUpdated {
 65                    old_range: 0..0,
 66                    new_count: 1
 67                }
 68            ]
 69        );
 70
 71        store.respond_to_notification(entry.notification.clone(), true, cx);
 72    });
 73
 74    // Client B sees the notification is now read, and that they responded.
 75    deterministic.run_until_parked();
 76    client_b.notification_store().read_with(cx_b, |store, _| {
 77        assert_eq!(store.notification_count(), 1);
 78        assert_eq!(store.unread_notification_count(), 0);
 79
 80        let entry = store.notification_at(0).unwrap();
 81        assert!(entry.is_read);
 82        assert_eq!(entry.response, Some(true));
 83        assert_eq!(
 84            &notification_events_b.lock()[2..],
 85            &[
 86                NotificationEvent::NotificationRead {
 87                    entry: entry.clone(),
 88                },
 89                NotificationEvent::NotificationsUpdated {
 90                    old_range: 0..1,
 91                    new_count: 1
 92                }
 93            ]
 94        );
 95    });
 96
 97    // Client A receives a notification that client B accepted their request.
 98    client_a.notification_store().read_with(cx_a, |store, _| {
 99        assert_eq!(store.notification_count(), 1);
100        assert_eq!(store.unread_notification_count(), 1);
101
102        let entry = store.notification_at(0).unwrap();
103        assert_eq!(
104            entry.notification,
105            Notification::ContactRequestAccepted {
106                responder_id: client_b.id()
107            }
108        );
109        assert!(!entry.is_read);
110    });
111
112    // Client A creates a channel and invites client B to be a member.
113    let channel_id = client_a
114        .channel_store()
115        .update(cx_a, |store, cx| {
116            store.create_channel("the-channel", None, cx)
117        })
118        .await
119        .unwrap();
120    client_a
121        .channel_store()
122        .update(cx_a, |store, cx| {
123            store.invite_member(channel_id, client_b.id(), proto::ChannelRole::Member, cx)
124        })
125        .await
126        .unwrap();
127
128    // Client B receives a channel invitation notification and responds to the
129    // invitation, accepting it.
130    deterministic.run_until_parked();
131    client_b.notification_store().update(cx_b, |store, cx| {
132        assert_eq!(store.notification_count(), 2);
133        assert_eq!(store.unread_notification_count(), 1);
134
135        let entry = store.notification_at(0).unwrap();
136        assert_eq!(
137            entry.notification,
138            Notification::ChannelInvitation {
139                channel_id,
140                channel_name: "the-channel".to_string(),
141                inviter_id: client_a.id()
142            }
143        );
144        assert!(!entry.is_read);
145
146        store.respond_to_notification(entry.notification.clone(), true, cx);
147    });
148
149    // Client B sees the notification is now read, and that they responded.
150    deterministic.run_until_parked();
151    client_b.notification_store().read_with(cx_b, |store, _| {
152        assert_eq!(store.notification_count(), 2);
153        assert_eq!(store.unread_notification_count(), 0);
154
155        let entry = store.notification_at(0).unwrap();
156        assert!(entry.is_read);
157        assert_eq!(entry.response, Some(true));
158    });
159}