From 91b237d3d335a569a2bb93ceb409447b9bec9944 Mon Sep 17 00:00:00 2001 From: Icaro Motta Date: Thu, 27 Oct 2022 16:21:41 -0300 Subject: [PATCH] Fix unbounded number of calls to fetch notifications (#14250) --- src/status_im/activity_center/core_test.cljs | 859 +++++++++--------- src/status_im/data_store/activities.cljs | 26 +- src/status_im/data_store/activities_test.cljs | 154 ++-- 3 files changed, 512 insertions(+), 527 deletions(-) diff --git a/src/status_im/activity_center/core_test.cljs b/src/status_im/activity_center/core_test.cljs index 8e01560b60..6072c9ac7c 100644 --- a/src/status_im/activity_center/core_test.cljs +++ b/src/status_im/activity_center/core_test.cljs @@ -5,503 +5,488 @@ [status-im.constants :as const] [status-im.ethereum.json-rpc :as json-rpc] status-im.events - [status-im.test-helpers :as h])) + [status-im.test-helpers :as h] + [status-im.utils.config :as config])) (defn setup [] (h/register-helper-events) (rf/dispatch [:init/app-started])) -(defn remove-color-key - "Remove `:color` key from notifications because they have random values that are - inconvenient to assert against." - [grouped-notifications {:keys [type status]}] - (update-in grouped-notifications - [type status :data] - (fn [old _] - (map #(dissoc % :color) old)) - nil)) - ;;;; Contact verification (deftest contact-verification-decline-test - (testing "successfully declines and reconciles returned notification" - (rf-test/run-test-sync - (setup) - (let [spy-queue (atom []) - contact-verification-id 24 - expected-notification {:accepted false - :author "0x04d03f" - :chat-id "0x04d03f" - :contact-verification-status 3 - :dismissed false - :id 24 - :last-message nil - :message {:command-parameters nil - :content {:chat-id nil - :ens-name nil - :image nil - :line-count nil - :links nil - :parsed-text nil - :response-to nil - :rtl? nil - :sticker nil - :text nil} - :outgoing false - :outgoing-status nil - :quoted-message nil} - :name "0x04d03f" - :read true - :reply-message nil - :timestamp 1666647286000 - :type const/activity-center-notification-type-contact-verification}] - (h/stub-fx-with-callbacks - ::json-rpc/call - :on-success (constantly {:activityCenterNotifications - [{:accepted false - :author "0x04d03f" - :chatId "0x04d03f" - :contactVerificationStatus 3 - :dismissed false - :id contact-verification-id - :message {} - :name "0x04d03f" - :read true - :timestamp 1666647286000 - :type const/activity-center-notification-type-contact-verification}]})) + (with-redefs [config/new-activity-center-enabled? true] + (testing "successfully declines and reconciles returned notification" + (rf-test/run-test-sync + (setup) + (let [spy-queue (atom []) + contact-verification-id 24 + expected-notification {:accepted false + :author "0x04d03f" + :chat-id "0x04d03f" + :contact-verification-status 3 + :dismissed false + :id 24 + :last-message nil + :message {:command-parameters nil + :content {:chat-id nil + :ens-name nil + :image nil + :line-count nil + :links nil + :parsed-text nil + :response-to nil + :rtl? nil + :sticker nil + :text nil} + :outgoing false + :outgoing-status nil + :quoted-message nil} + :name "0x04d03f" + :read true + :reply-message nil + :timestamp 1666647286000 + :type const/activity-center-notification-type-contact-verification}] + (h/stub-fx-with-callbacks + ::json-rpc/call + :on-success (constantly {:activityCenterNotifications + [{:accepted false + :author "0x04d03f" + :chatId "0x04d03f" + :contactVerificationStatus 3 + :dismissed false + :id contact-verification-id + :message {} + :name "0x04d03f" + :read true + :timestamp 1666647286000 + :type const/activity-center-notification-type-contact-verification}]})) - (h/spy-fx spy-queue ::json-rpc/call) + (h/spy-fx spy-queue ::json-rpc/call) - (rf/dispatch [:activity-center.contact-verification/decline contact-verification-id]) + (rf/dispatch [:activity-center.contact-verification/decline contact-verification-id]) - (is (= {:method "wakuext_declineContactVerificationRequest" - :params [contact-verification-id]} - (-> @spy-queue - (get-in [0 :args 0]) - (select-keys [:method :params])))) + (is (= {:method "wakuext_declineContactVerificationRequest" + :params [contact-verification-id]} + (-> @spy-queue + (get-in [0 :args 0]) + (select-keys [:method :params])))) - (is (= {const/activity-center-notification-type-no-type - {:read {:data [expected-notification]} - :unread {:data []}} - const/activity-center-notification-type-contact-verification - {:read {:data [expected-notification]} - :unread {:data []}}} - (-> (h/db) - (get-in [:activity-center :notifications]) - (remove-color-key {:type const/activity-center-notification-type-no-type - :status :read}) - (remove-color-key {:type const/activity-center-notification-type-contact-verification - :status :read}))))))) + (is (= {const/activity-center-notification-type-no-type + {:read {:data [expected-notification]} + :unread {:data []}} + const/activity-center-notification-type-contact-verification + {:read {:data [expected-notification]} + :unread {:data []}}} + (get-in (h/db) [:activity-center :notifications])))))) - (testing "logs failure" - (rf-test/run-test-sync - (setup) - (let [contact-verification-id 666] - (h/using-log-test-appender - (fn [logs] - (h/stub-fx-with-callbacks ::json-rpc/call :on-error (constantly :fake-error)) + (testing "logs failure" + (rf-test/run-test-sync + (setup) + (let [contact-verification-id 666] + (h/using-log-test-appender + (fn [logs] + (h/stub-fx-with-callbacks ::json-rpc/call :on-error (constantly :fake-error)) - (rf/dispatch [:activity-center.contact-verification/decline contact-verification-id]) + (rf/dispatch [:activity-center.contact-verification/decline contact-verification-id]) - (is (= {:args ["Failed to decline contact verification" - {:contact-verification-id contact-verification-id - :error :fake-error}] - :level :warn} - (last @logs))))))))) + (is (= {:args ["Failed to decline contact verification" + {:contact-verification-id contact-verification-id + :error :fake-error}] + :level :warn} + (last @logs)))))))))) ;;;; Notification reconciliation (deftest notifications-reconcile-test - (testing "does nothing when there are no new notifications" - (rf-test/run-test-sync - (setup) - (let [notifications {const/activity-center-notification-type-one-to-one-chat - {:read {:cursor "" - :data [{:id "0x1" - :read true - :type const/activity-center-notification-type-one-to-one-chat} - {:id "0x2" - :read true - :type const/activity-center-notification-type-one-to-one-chat}]} - :unread {:cursor "" - :data [{:id "0x3" - :read false - :type const/activity-center-notification-type-one-to-one-chat}]}} - const/activity-center-notification-type-private-group-chat - {:unread {:cursor "" - :data [{:id "0x4" - :read false - :type const/activity-center-notification-type-private-group-chat}]}}}] - (rf/dispatch [:test/assoc-in [:activity-center :notifications] notifications]) + (with-redefs [config/new-activity-center-enabled? true] + (testing "does nothing when there are no new notifications" + (rf-test/run-test-sync + (setup) + (let [notifications {const/activity-center-notification-type-one-to-one-chat + {:read {:cursor "" + :data [{:id "0x1" + :read true + :type const/activity-center-notification-type-one-to-one-chat} + {:id "0x2" + :read true + :type const/activity-center-notification-type-one-to-one-chat}]} + :unread {:cursor "" + :data [{:id "0x3" + :read false + :type const/activity-center-notification-type-one-to-one-chat}]}} + const/activity-center-notification-type-private-group-chat + {:unread {:cursor "" + :data [{:id "0x4" + :read false + :type const/activity-center-notification-type-private-group-chat}]}}}] + (rf/dispatch [:test/assoc-in [:activity-center :notifications] notifications]) - (rf/dispatch [:activity-center.notifications/reconcile nil]) + (rf/dispatch [:activity-center.notifications/reconcile nil]) - (is (= notifications (get-in (h/db) [:activity-center :notifications])))))) + (is (= notifications (get-in (h/db) [:activity-center :notifications])))))) - (testing "removes dismissed or accepted notifications" - (rf-test/run-test-sync - (setup) - (rf/dispatch [:test/assoc-in [:activity-center :notifications] - {const/activity-center-notification-type-one-to-one-chat - {:read {:cursor "" - :data [{:id "0x1" :read true :type const/activity-center-notification-type-one-to-one-chat} - {:id "0x2" :read true :type const/activity-center-notification-type-one-to-one-chat}]} - :unread {:cursor "" - :data [{:id "0x3" :read false :type const/activity-center-notification-type-one-to-one-chat}]}} - const/activity-center-notification-type-private-group-chat - {:unread {:cursor "" - :data [{:id "0x4" :read false :type const/activity-center-notification-type-private-group-chat} - {:id "0x6" :read false :type const/activity-center-notification-type-private-group-chat}]}}}]) + (testing "removes dismissed or accepted notifications" + (rf-test/run-test-sync + (setup) + (rf/dispatch [:test/assoc-in [:activity-center :notifications] + {const/activity-center-notification-type-one-to-one-chat + {:read {:cursor "" + :data [{:id "0x1" :read true :type const/activity-center-notification-type-one-to-one-chat} + {:id "0x2" :read true :type const/activity-center-notification-type-one-to-one-chat}]} + :unread {:cursor "" + :data [{:id "0x3" :read false :type const/activity-center-notification-type-one-to-one-chat}]}} + const/activity-center-notification-type-private-group-chat + {:unread {:cursor "" + :data [{:id "0x4" :read false :type const/activity-center-notification-type-private-group-chat} + {:id "0x6" :read false :type const/activity-center-notification-type-private-group-chat}]}}}]) - (rf/dispatch [:activity-center.notifications/reconcile - [{:id "0x1" - :read true - :type const/activity-center-notification-type-one-to-one-chat - :dismissed true} - {:id "0x3" - :read false - :type const/activity-center-notification-type-one-to-one-chat - :accepted true} - {:id "0x4" - :read false - :type const/activity-center-notification-type-private-group-chat - :dismissed true} - {:id "0x5" - :read false - :type const/activity-center-notification-type-private-group-chat - :accepted true}]]) + (rf/dispatch [:activity-center.notifications/reconcile + [{:id "0x1" + :read true + :type const/activity-center-notification-type-one-to-one-chat + :dismissed true} + {:id "0x3" + :read false + :type const/activity-center-notification-type-one-to-one-chat + :accepted true} + {:id "0x4" + :read false + :type const/activity-center-notification-type-private-group-chat + :dismissed true} + {:id "0x5" + :read false + :type const/activity-center-notification-type-private-group-chat + :accepted true}]]) - (is (= {const/activity-center-notification-type-no-type - {:read {:data []} - :unread {:data []}} + (is (= {const/activity-center-notification-type-no-type + {:read {:data []} + :unread {:data []}} - const/activity-center-notification-type-one-to-one-chat - {:read {:cursor "" - :data [{:id "0x2" - :read true - :type const/activity-center-notification-type-one-to-one-chat}]} - :unread {:cursor "" - :data []}} - const/activity-center-notification-type-private-group-chat - {:read {:data []} - :unread {:cursor "" - :data [{:id "0x6" - :read false - :type const/activity-center-notification-type-private-group-chat}]}}} - (get-in (h/db) [:activity-center :notifications]))))) + const/activity-center-notification-type-one-to-one-chat + {:read {:cursor "" + :data [{:id "0x2" + :read true + :type const/activity-center-notification-type-one-to-one-chat}]} + :unread {:cursor "" + :data []}} + const/activity-center-notification-type-private-group-chat + {:read {:data []} + :unread {:cursor "" + :data [{:id "0x6" + :read false + :type const/activity-center-notification-type-private-group-chat}]}}} + (get-in (h/db) [:activity-center :notifications]))))) - (testing "replaces old notifications with newly arrived ones" - (rf-test/run-test-sync - (setup) - (rf/dispatch [:test/assoc-in [:activity-center :notifications] - {const/activity-center-notification-type-no-type - {:read {:cursor "" + (testing "replaces old notifications with newly arrived ones" + (rf-test/run-test-sync + (setup) + (rf/dispatch [:test/assoc-in [:activity-center :notifications] + {const/activity-center-notification-type-no-type + {:read {:cursor "" + :data [{:id "0x1" + :read true + :type const/activity-center-notification-type-one-to-one-chat}]} + :unread {:cursor "" + :data [{:id "0x4" + :read false + :type const/activity-center-notification-type-private-group-chat} + {:id "0x6" + :read false + :type const/activity-center-notification-type-private-group-chat}]}} + const/activity-center-notification-type-one-to-one-chat + {:read {:cursor "" :data [{:id "0x1" :read true - :type const/activity-center-notification-type-one-to-one-chat}]} - :unread {:cursor "" - :data [{:id "0x4" - :read false - :type const/activity-center-notification-type-private-group-chat} - {:id "0x6" - :read false - :type const/activity-center-notification-type-private-group-chat}]}} - const/activity-center-notification-type-one-to-one-chat - {:read {:cursor "" - :data [{:id "0x1" - :read true - :type const/activity-center-notification-type-one-to-one-chat}]}} - const/activity-center-notification-type-private-group-chat - {:unread {:cursor "" - :data [{:id "0x4" - :read false - :type const/activity-center-notification-type-private-group-chat} - {:id "0x6" - :read false - :type const/activity-center-notification-type-private-group-chat}]}}}]) + :type const/activity-center-notification-type-one-to-one-chat}]}} + const/activity-center-notification-type-private-group-chat + {:unread {:cursor "" + :data [{:id "0x4" + :read false + :type const/activity-center-notification-type-private-group-chat} + {:id "0x6" + :read false + :type const/activity-center-notification-type-private-group-chat}]}}}]) - (rf/dispatch [:activity-center.notifications/reconcile - [{:id "0x1" - :read true - :type const/activity-center-notification-type-one-to-one-chat - :last-message {}} - {:id "0x4" - :read false - :type const/activity-center-notification-type-private-group-chat - :author "0xabc"} - {:id "0x6" - :read false - :type const/activity-center-notification-type-private-group-chat}]]) + (rf/dispatch [:activity-center.notifications/reconcile + [{:id "0x1" + :read true + :type const/activity-center-notification-type-one-to-one-chat + :last-message {}} + {:id "0x4" + :read false + :type const/activity-center-notification-type-private-group-chat + :author "0xabc"} + {:id "0x6" + :read false + :type const/activity-center-notification-type-private-group-chat}]]) - (is (= {const/activity-center-notification-type-no-type - {:read {:cursor "" - :data [{:id "0x1" - :read true - :type const/activity-center-notification-type-one-to-one-chat - :last-message {}}]} - :unread {:cursor "" - :data [{:id "0x6" + (is (= {const/activity-center-notification-type-no-type + {:read {:cursor "" + :data [{:id "0x1" + :read true + :type const/activity-center-notification-type-one-to-one-chat + :last-message {}}]} + :unread {:cursor "" + :data [{:id "0x6" + :read false + :type const/activity-center-notification-type-private-group-chat} + {:id "0x4" + :read false + :type const/activity-center-notification-type-private-group-chat + :author "0xabc"}]}} + const/activity-center-notification-type-one-to-one-chat + {:read {:cursor "" + :data [{:id "0x1" + :read true + :type const/activity-center-notification-type-one-to-one-chat + :last-message {}}]} + :unread {:data []}} + const/activity-center-notification-type-private-group-chat + {:read {:data []} + :unread {:cursor "" + :data [{:id "0x6" + :read false + :type const/activity-center-notification-type-private-group-chat} + {:id "0x4" + :read false + :type const/activity-center-notification-type-private-group-chat + :author "0xabc"}]}}} + (get-in (h/db) [:activity-center :notifications]))))) + + (testing "reconciles notifications that switched their read/unread status" + (rf-test/run-test-sync + (setup) + (rf/dispatch [:test/assoc-in [:activity-center :notifications] + {const/activity-center-notification-type-one-to-one-chat + {:read {:cursor "" + :data [{:id "0x1" + :read true + :type const/activity-center-notification-type-one-to-one-chat}]}}}]) + + (rf/dispatch [:activity-center.notifications/reconcile + [{:id "0x1" + :read false + :type const/activity-center-notification-type-one-to-one-chat}]]) + + (is (= {const/activity-center-notification-type-no-type + {:read {:data []} + :unread {:data [{:id "0x1" :read false - :type const/activity-center-notification-type-private-group-chat} - {:id "0x4" - :read false - :type const/activity-center-notification-type-private-group-chat - :author "0xabc"}]}} - const/activity-center-notification-type-one-to-one-chat - {:read {:cursor "" - :data [{:id "0x1" - :read true - :type const/activity-center-notification-type-one-to-one-chat - :last-message {}}]} - :unread {:data []}} - const/activity-center-notification-type-private-group-chat - {:read {:data []} - :unread {:cursor "" - :data [{:id "0x6" + :type const/activity-center-notification-type-one-to-one-chat}]}} + + const/activity-center-notification-type-one-to-one-chat + {:read {:cursor "" + :data []} + :unread {:data [{:id "0x1" :read false - :type const/activity-center-notification-type-private-group-chat} - {:id "0x4" - :read false - :type const/activity-center-notification-type-private-group-chat - :author "0xabc"}]}}} - (get-in (h/db) [:activity-center :notifications]))))) + :type const/activity-center-notification-type-one-to-one-chat}]}}} + (get-in (h/db) [:activity-center :notifications]))))) - (testing "reconciles notifications that switched their read/unread status" - (rf-test/run-test-sync - (setup) - (rf/dispatch [:test/assoc-in [:activity-center :notifications] - {const/activity-center-notification-type-one-to-one-chat - {:read {:cursor "" - :data [{:id "0x1" - :read true - :type const/activity-center-notification-type-one-to-one-chat}]}}}]) + ;; Sorting by timestamp and ID is compatible with what the backend does when + ;; returning paginated results. + (testing "sorts notifications by timestamp and id in descending order" + (rf-test/run-test-sync + (setup) + (rf/dispatch [:test/assoc-in [:activity-center :notifications] + {const/activity-center-notification-type-one-to-one-chat + {:read {:cursor "" + :data [{:id "0x1" :read true :type const/activity-center-notification-type-one-to-one-chat :timestamp 1} + {:id "0x2" :read true :type const/activity-center-notification-type-one-to-one-chat :timestamp 1}]} + :unread {:cursor "" + :data [{:id "0x3" :read false :type const/activity-center-notification-type-one-to-one-chat :timestamp 50} + {:id "0x4" :read false :type const/activity-center-notification-type-one-to-one-chat :timestamp 100} + {:id "0x5" :read false :type const/activity-center-notification-type-one-to-one-chat :timestamp 100}]}}}]) - (rf/dispatch [:activity-center.notifications/reconcile - [{:id "0x1" - :read false - :type const/activity-center-notification-type-one-to-one-chat}]]) + (rf/dispatch [:activity-center.notifications/reconcile + [{:id "0x1" :read true :type const/activity-center-notification-type-one-to-one-chat :timestamp 1 :last-message {}} + {:id "0x4" :read false :type const/activity-center-notification-type-one-to-one-chat :timestamp 100 :last-message {}}]]) - (is (= {const/activity-center-notification-type-no-type - {:read {:data []} - :unread {:data [{:id "0x1" - :read false - :type const/activity-center-notification-type-one-to-one-chat}]}} - - const/activity-center-notification-type-one-to-one-chat - {:read {:cursor "" - :data []} - :unread {:data [{:id "0x1" - :read false - :type const/activity-center-notification-type-one-to-one-chat}]}}} - (get-in (h/db) [:activity-center :notifications]))))) - - ;; Sorting by timestamp and ID is compatible with what the backend does when - ;; returning paginated results. - (testing "sorts notifications by timestamp and id in descending order" - (rf-test/run-test-sync - (setup) - (rf/dispatch [:test/assoc-in [:activity-center :notifications] - {const/activity-center-notification-type-one-to-one-chat - {:read {:cursor "" - :data [{:id "0x1" :read true :type const/activity-center-notification-type-one-to-one-chat :timestamp 1} - {:id "0x2" :read true :type const/activity-center-notification-type-one-to-one-chat :timestamp 1}]} - :unread {:cursor "" - :data [{:id "0x3" :read false :type const/activity-center-notification-type-one-to-one-chat :timestamp 50} - {:id "0x4" :read false :type const/activity-center-notification-type-one-to-one-chat :timestamp 100} - {:id "0x5" :read false :type const/activity-center-notification-type-one-to-one-chat :timestamp 100}]}}}]) - - (rf/dispatch [:activity-center.notifications/reconcile - [{:id "0x1" :read true :type const/activity-center-notification-type-one-to-one-chat :timestamp 1 :last-message {}} - {:id "0x4" :read false :type const/activity-center-notification-type-one-to-one-chat :timestamp 100 :last-message {}}]]) - - (is (= {const/activity-center-notification-type-no-type - {:read {:data [{:id "0x1" - :read true - :type const/activity-center-notification-type-one-to-one-chat - :timestamp 1 - :last-message {}}]} - :unread {:data [{:id "0x4" - :read false - :type const/activity-center-notification-type-one-to-one-chat - :timestamp 100 - :last-message {}}]}} - const/activity-center-notification-type-one-to-one-chat - {:read {:cursor "" - :data [{:id "0x2" - :read true - :type const/activity-center-notification-type-one-to-one-chat - :timestamp 1} - {:id "0x1" + (is (= {const/activity-center-notification-type-no-type + {:read {:data [{:id "0x1" :read true :type const/activity-center-notification-type-one-to-one-chat :timestamp 1 :last-message {}}]} - :unread {:cursor "" - :data [{:id "0x5" - :read false - :type const/activity-center-notification-type-one-to-one-chat - :timestamp 100} - {:id "0x4" + :unread {:data [{:id "0x4" :read false :type const/activity-center-notification-type-one-to-one-chat :timestamp 100 - :last-message {}} - {:id "0x3" - :read false - :type const/activity-center-notification-type-one-to-one-chat - :timestamp 50}]}}} - (get-in (h/db) [:activity-center :notifications])))))) + :last-message {}}]}} + const/activity-center-notification-type-one-to-one-chat + {:read {:cursor "" + :data [{:id "0x2" + :read true + :type const/activity-center-notification-type-one-to-one-chat + :timestamp 1} + {:id "0x1" + :read true + :type const/activity-center-notification-type-one-to-one-chat + :timestamp 1 + :last-message {}}]} + :unread {:cursor "" + :data [{:id "0x5" + :read false + :type const/activity-center-notification-type-one-to-one-chat + :timestamp 100} + {:id "0x4" + :read false + :type const/activity-center-notification-type-one-to-one-chat + :timestamp 100 + :last-message {}} + {:id "0x3" + :read false + :type const/activity-center-notification-type-one-to-one-chat + :timestamp 50}]}}} + (get-in (h/db) [:activity-center :notifications]))))))) ;;;; Notifications fetching and pagination (deftest notifications-fetch-test - (testing "fetches first page" - (rf-test/run-test-sync - (setup) - (let [spy-queue (atom [])] - (h/stub-fx-with-callbacks - ::json-rpc/call - :on-success (constantly {:cursor "10" - :notifications [{:id "0x1" - :type const/activity-center-notification-type-one-to-one-chat - :read false - :chatId "0x9"}]})) - (h/spy-fx spy-queue ::json-rpc/call) + (with-redefs [config/new-activity-center-enabled? true] + (testing "fetches first page" + (rf-test/run-test-sync + (setup) + (let [spy-queue (atom [])] + (h/stub-fx-with-callbacks + ::json-rpc/call + :on-success (constantly {:cursor "10" + :notifications [{:id "0x1" + :type const/activity-center-notification-type-one-to-one-chat + :read false + :chatId "0x9"}]})) + (h/spy-fx spy-queue ::json-rpc/call) - (rf/dispatch [:activity-center.notifications/fetch-first-page - {:filter-type const/activity-center-notification-type-one-to-one-chat}]) + (rf/dispatch [:activity-center.notifications/fetch-first-page + {:filter-type const/activity-center-notification-type-one-to-one-chat}]) - (is (= :unread (get-in (h/db) [:activity-center :filter :status]))) - (is (= "" (get-in @spy-queue [0 :args 0 :params 0])) - "Should be called with empty cursor when fetching first page") - (is (= {const/activity-center-notification-type-one-to-one-chat - {:unread {:cursor "10" - :data [{:chat-id "0x9" - :chat-name nil - :chat-type const/activity-center-notification-type-one-to-one-chat - :group-chat false - :id "0x1" - :public? false - :last-message nil - :message nil - :read false - :reply-message nil - :type const/activity-center-notification-type-one-to-one-chat}]}}} - (remove-color-key (get-in (h/db) [:activity-center :notifications]) - {:status :unread - :type const/activity-center-notification-type-one-to-one-chat})))))) + (is (= :unread (get-in (h/db) [:activity-center :filter :status]))) + (is (= "" (get-in @spy-queue [0 :args 0 :params 0])) + "Should be called with empty cursor when fetching first page") + (is (= {const/activity-center-notification-type-one-to-one-chat + {:unread {:cursor "10" + :data [{:chat-id "0x9" + :chat-name nil + :chat-type const/activity-center-notification-type-one-to-one-chat + :group-chat false + :id "0x1" + :public? false + :last-message nil + :message nil + :read false + :reply-message nil + :type const/activity-center-notification-type-one-to-one-chat}]}}} + (get-in (h/db) [:activity-center :notifications])))))) - (testing "does not fetch next page when pagination cursor reached the end" - (rf-test/run-test-sync - (setup) - (let [spy-queue (atom [])] - (h/spy-fx spy-queue ::json-rpc/call) - (rf/dispatch [:test/assoc-in [:activity-center :filter :status] - :unread]) - (rf/dispatch [:test/assoc-in [:activity-center :filter :type] - const/activity-center-notification-type-one-to-one-chat]) - (rf/dispatch [:test/assoc-in [:activity-center :notifications const/activity-center-notification-type-one-to-one-chat :unread :cursor] - ""]) + (testing "does not fetch next page when pagination cursor reached the end" + (rf-test/run-test-sync + (setup) + (let [spy-queue (atom [])] + (h/spy-fx spy-queue ::json-rpc/call) + (rf/dispatch [:test/assoc-in [:activity-center :filter :status] + :unread]) + (rf/dispatch [:test/assoc-in [:activity-center :filter :type] + const/activity-center-notification-type-one-to-one-chat]) + (rf/dispatch [:test/assoc-in [:activity-center :notifications const/activity-center-notification-type-one-to-one-chat :unread :cursor] + ""]) - (rf/dispatch [:activity-center.notifications/fetch-next-page]) + (rf/dispatch [:activity-center.notifications/fetch-next-page]) - (is (= [] @spy-queue))))) + (is (= [] @spy-queue))))) - ;; The cursor can be nil sometimes because the reconciliation doesn't care - ;; about updating the cursor value, but we have to make sure the next page is - ;; only fetched if the current cursor is valid. - (testing "does not fetch next page when cursor is nil" - (rf-test/run-test-sync - (setup) - (let [spy-queue (atom [])] - (h/spy-fx spy-queue ::json-rpc/call) - (rf/dispatch [:test/assoc-in [:activity-center :filter :status] - :unread]) - (rf/dispatch [:test/assoc-in [:activity-center :filter :type] - const/activity-center-notification-type-one-to-one-chat]) - (rf/dispatch [:test/assoc-in [:activity-center :notifications const/activity-center-notification-type-one-to-one-chat :unread :cursor] - nil]) + ;; The cursor can be nil sometimes because the reconciliation doesn't care + ;; about updating the cursor value, but we have to make sure the next page is + ;; only fetched if the current cursor is valid. + (testing "does not fetch next page when cursor is nil" + (rf-test/run-test-sync + (setup) + (let [spy-queue (atom [])] + (h/spy-fx spy-queue ::json-rpc/call) + (rf/dispatch [:test/assoc-in [:activity-center :filter :status] + :unread]) + (rf/dispatch [:test/assoc-in [:activity-center :filter :type] + const/activity-center-notification-type-one-to-one-chat]) + (rf/dispatch [:test/assoc-in [:activity-center :notifications const/activity-center-notification-type-one-to-one-chat :unread :cursor] + nil]) - (rf/dispatch [:activity-center.notifications/fetch-next-page]) + (rf/dispatch [:activity-center.notifications/fetch-next-page]) - (is (= [] @spy-queue))))) + (is (= [] @spy-queue))))) - (testing "fetches next page when pagination cursor is not empty" - (rf-test/run-test-sync - (setup) - (let [spy-queue (atom [])] - (h/stub-fx-with-callbacks - ::json-rpc/call - :on-success (constantly {:cursor "" - :notifications [{:id "0x1" - :type const/activity-center-notification-type-mention - :read false - :chatId "0x9"}]})) - (h/spy-fx spy-queue ::json-rpc/call) - (rf/dispatch [:test/assoc-in [:activity-center :filter :status] - :unread]) - (rf/dispatch [:test/assoc-in [:activity-center :filter :type] - const/activity-center-notification-type-mention]) - (rf/dispatch [:test/assoc-in [:activity-center :notifications const/activity-center-notification-type-mention :unread :cursor] - "10"]) + (testing "fetches next page when pagination cursor is not empty" + (rf-test/run-test-sync + (setup) + (let [spy-queue (atom [])] + (h/stub-fx-with-callbacks + ::json-rpc/call + :on-success (constantly {:cursor "" + :notifications [{:id "0x1" + :type const/activity-center-notification-type-mention + :read false + :chatId "0x9"}]})) + (h/spy-fx spy-queue ::json-rpc/call) + (rf/dispatch [:test/assoc-in [:activity-center :filter :status] + :unread]) + (rf/dispatch [:test/assoc-in [:activity-center :filter :type] + const/activity-center-notification-type-mention]) + (rf/dispatch [:test/assoc-in [:activity-center :notifications const/activity-center-notification-type-mention :unread :cursor] + "10"]) - (rf/dispatch [:activity-center.notifications/fetch-next-page]) + (rf/dispatch [:activity-center.notifications/fetch-next-page]) - (is (= "wakuext_unreadActivityCenterNotifications" (get-in @spy-queue [0 :args 0 :method]))) - (is (= "10" (get-in @spy-queue [0 :args 0 :params 0])) - "Should be called with current cursor") - (is (= {const/activity-center-notification-type-mention - {:unread {:cursor "" - :data [{:chat-id "0x9" - :chat-name nil - :chat-type 3 - :id "0x1" - :last-message nil - :message nil - :read false - :reply-message nil - :type const/activity-center-notification-type-mention}]}}} - (remove-color-key (get-in (h/db) [:activity-center :notifications]) - {:status :unread - :type const/activity-center-notification-type-mention})))))) + (is (= "wakuext_unreadActivityCenterNotifications" (get-in @spy-queue [0 :args 0 :method]))) + (is (= "10" (get-in @spy-queue [0 :args 0 :params 0])) + "Should be called with current cursor") + (is (= {const/activity-center-notification-type-mention + {:unread {:cursor "" + :data [{:chat-id "0x9" + :chat-name nil + :chat-type 3 + :id "0x1" + :last-message nil + :message nil + :read false + :reply-message nil + :type const/activity-center-notification-type-mention}]}}} + (get-in (h/db) [:activity-center :notifications])))))) - (testing "does not fetch next page while it is still loading" - (rf-test/run-test-sync - (setup) - (let [spy-queue (atom [])] - (h/spy-fx spy-queue ::json-rpc/call) - (rf/dispatch [:test/assoc-in [:activity-center :filter :status] - :read]) - (rf/dispatch [:test/assoc-in [:activity-center :filter :type] - const/activity-center-notification-type-one-to-one-chat]) - (rf/dispatch [:test/assoc-in [:activity-center :notifications const/activity-center-notification-type-one-to-one-chat :read :cursor] - "10"]) - (rf/dispatch [:test/assoc-in [:activity-center :notifications const/activity-center-notification-type-one-to-one-chat :read :loading?] - true]) + (testing "does not fetch next page while it is still loading" + (rf-test/run-test-sync + (setup) + (let [spy-queue (atom [])] + (h/spy-fx spy-queue ::json-rpc/call) + (rf/dispatch [:test/assoc-in [:activity-center :filter :status] + :read]) + (rf/dispatch [:test/assoc-in [:activity-center :filter :type] + const/activity-center-notification-type-one-to-one-chat]) + (rf/dispatch [:test/assoc-in [:activity-center :notifications const/activity-center-notification-type-one-to-one-chat :read :cursor] + "10"]) + (rf/dispatch [:test/assoc-in [:activity-center :notifications const/activity-center-notification-type-one-to-one-chat :read :loading?] + true]) - (rf/dispatch [:activity-center.notifications/fetch-next-page]) + (rf/dispatch [:activity-center.notifications/fetch-next-page]) - (is (= [] @spy-queue))))) + (is (= [] @spy-queue))))) - (testing "resets loading flag after an error" - (rf-test/run-test-sync - (setup) - (let [spy-queue (atom [])] - (h/stub-fx-with-callbacks ::json-rpc/call :on-error (constantly :fake-error)) - (h/spy-event-fx spy-queue :activity-center.notifications/fetch-error) - (h/spy-fx spy-queue ::json-rpc/call) - (rf/dispatch [:test/assoc-in [:activity-center :filter :status] - :unread]) - (rf/dispatch [:test/assoc-in [:activity-center :filter :type] - const/activity-center-notification-type-one-to-one-chat]) - (rf/dispatch [:test/assoc-in [:activity-center :notifications const/activity-center-notification-type-one-to-one-chat :unread :cursor] - ""]) + (testing "resets loading flag after an error" + (rf-test/run-test-sync + (setup) + (let [spy-queue (atom [])] + (h/stub-fx-with-callbacks ::json-rpc/call :on-error (constantly :fake-error)) + (h/spy-event-fx spy-queue :activity-center.notifications/fetch-error) + (h/spy-fx spy-queue ::json-rpc/call) + (rf/dispatch [:test/assoc-in [:activity-center :filter :status] + :unread]) + (rf/dispatch [:test/assoc-in [:activity-center :filter :type] + const/activity-center-notification-type-one-to-one-chat]) + (rf/dispatch [:test/assoc-in [:activity-center :notifications const/activity-center-notification-type-one-to-one-chat :unread :cursor] + ""]) - (rf/dispatch [:activity-center.notifications/fetch-first-page]) + (rf/dispatch [:activity-center.notifications/fetch-first-page]) - (is (nil? (get-in (h/db) [:activity-center :notifications const/activity-center-notification-type-one-to-one-chat :unread :loading?]))) - (is (= [:activity-center.notifications/fetch-error - const/activity-center-notification-type-one-to-one-chat - :unread - :fake-error] - (:args (last @spy-queue)))))))) + (is (nil? (get-in (h/db) [:activity-center :notifications const/activity-center-notification-type-one-to-one-chat :unread :loading?]))) + (is (= [:activity-center.notifications/fetch-error + const/activity-center-notification-type-one-to-one-chat + :unread + :fake-error] + (:args (last @spy-queue))))))))) diff --git a/src/status_im/data_store/activities.cljs b/src/status_im/data_store/activities.cljs index 2e26ebe283..efcd446360 100644 --- a/src/status_im/data_store/activities.cljs +++ b/src/status_im/data_store/activities.cljs @@ -2,7 +2,8 @@ (:require [clojure.set :as set] [quo.design-system.colors :as colors] [status-im.constants :as constants] - [status-im.data-store.messages :as messages])) + [status-im.data-store.messages :as messages] + [status-im.utils.config :as config])) (defn- rpc->type [{:keys [type name] :as chat}] (case type @@ -33,14 +34,15 @@ chat)) (defn <-rpc [item] - (-> item - rpc->type - (set/rename-keys {:lastMessage :last-message - :replyMessage :reply-message - :chatId :chat-id - :contactVerificationStatus :contact-verification-status}) - (assoc :color (rand-nth colors/chat-colors)) - (update :last-message #(when % (messages/<-rpc %))) - (update :message #(when % (messages/<-rpc %))) - (update :reply-message #(when % (messages/<-rpc %))) - (dissoc :chatId))) + (cond-> (-> item + rpc->type + (set/rename-keys {:lastMessage :last-message + :replyMessage :reply-message + :chatId :chat-id + :contactVerificationStatus :contact-verification-status}) + (update :last-message #(when % (messages/<-rpc %))) + (update :message #(when % (messages/<-rpc %))) + (update :reply-message #(when % (messages/<-rpc %))) + (dissoc :chatId)) + (not config/new-activity-center-enabled?) + (assoc :color (rand-nth colors/chat-colors)))) diff --git a/src/status_im/data_store/activities_test.cljs b/src/status_im/data_store/activities_test.cljs index b79ec109dd..3274f4b642 100644 --- a/src/status_im/data_store/activities_test.cljs +++ b/src/status_im/data_store/activities_test.cljs @@ -1,8 +1,8 @@ (ns status-im.data-store.activities-test (:require [cljs.test :refer [deftest is testing]] - [quo.design-system.colors :as colors] [status-im.constants :as constants] - [status-im.data-store.activities :as store])) + [status-im.data-store.activities :as store] + [status-im.utils.config :as config])) (def chat-id "0x04c66155") @@ -18,84 +18,82 @@ :replyMessage {}}) (deftest <-rpc-test - (testing "assocs random chat color" - (is (contains? (set colors/chat-colors) (:color (store/<-rpc raw-notification))))) + (with-redefs [config/new-activity-center-enabled? true] + (testing "renames keys" + (is (= {:name chat-name + :chat-id chat-id + :contact-verification-status constants/contact-verification-state-pending} + (-> raw-notification + store/<-rpc + (dissoc :last-message :message :reply-message))))) - (testing "renames keys" - (is (= {:name chat-name - :chat-id chat-id - :contact-verification-status constants/contact-verification-state-pending} - (-> raw-notification - store/<-rpc - (dissoc :color :last-message :message :reply-message))))) + (testing "transforms messages from RPC response" + (is (= {:last-message {:quoted-message nil + :outgoing-status nil + :command-parameters nil + :content {:sticker nil + :rtl? nil + :ens-name nil + :parsed-text nil + :response-to nil + :chat-id nil + :image nil + :line-count nil + :links nil + :text nil} + :outgoing false} + :message nil + :reply-message {:quoted-message nil + :outgoing-status nil + :command-parameters nil + :content {:sticker nil + :rtl? nil + :ens-name nil + :parsed-text nil + :response-to nil + :chat-id nil + :image nil + :line-count nil + :links nil + :text nil} + :outgoing false}} + (-> raw-notification + store/<-rpc + (select-keys [:last-message :message :reply-message]))))) - (testing "transforms messages from RPC response" - (is (= {:last-message {:quoted-message nil - :outgoing-status nil - :command-parameters nil - :content {:sticker nil - :rtl? nil - :ens-name nil - :parsed-text nil - :response-to nil - :chat-id nil - :image nil - :line-count nil - :links nil - :text nil} - :outgoing false} - :message nil - :reply-message {:quoted-message nil - :outgoing-status nil - :command-parameters nil - :content {:sticker nil - :rtl? nil - :ens-name nil - :parsed-text nil - :response-to nil - :chat-id nil - :image nil - :line-count nil - :links nil - :text nil} - :outgoing false}} - (-> raw-notification - store/<-rpc - (select-keys [:last-message :message :reply-message]))))) + (testing "augments notification based on its type" + (is (= {:chat-name chat-name + :chat-type constants/private-group-chat-type + :name chat-name} + (-> raw-notification + (assoc :type constants/activity-center-notification-type-reply) + store/<-rpc + (select-keys [:name :chat-type :chat-name :public? :group-chat])))) - (testing "augments notification based on its type" - (is (= {:chat-name chat-name - :chat-type constants/private-group-chat-type - :name chat-name} - (-> raw-notification - (assoc :type constants/activity-center-notification-type-reply) - store/<-rpc - (select-keys [:name :chat-type :chat-name :public? :group-chat])))) + (is (= {:chat-name chat-name + :chat-type constants/private-group-chat-type + :name chat-name} + (-> raw-notification + (assoc :type constants/activity-center-notification-type-mention) + store/<-rpc + (select-keys [:name :chat-type :chat-name :public? :group-chat])))) - (is (= {:chat-name chat-name - :chat-type constants/private-group-chat-type - :name chat-name} - (-> raw-notification - (assoc :type constants/activity-center-notification-type-mention) - store/<-rpc - (select-keys [:name :chat-type :chat-name :public? :group-chat])))) + (is (= {:chat-name chat-name + :chat-type constants/private-group-chat-type + :group-chat true + :name chat-name + :public? false} + (-> raw-notification + (assoc :type constants/activity-center-notification-type-private-group-chat) + store/<-rpc + (select-keys [:name :chat-type :chat-name :public? :group-chat])))) - (is (= {:chat-name chat-name - :chat-type constants/private-group-chat-type - :group-chat true - :name chat-name - :public? false} - (-> raw-notification - (assoc :type constants/activity-center-notification-type-private-group-chat) - store/<-rpc - (select-keys [:name :chat-type :chat-name :public? :group-chat])))) - - (is (= {:chat-name chat-name - :chat-type constants/one-to-one-chat-type - :group-chat false - :name chat-name - :public? false} - (-> raw-notification - (assoc :type constants/activity-center-notification-type-one-to-one-chat) - store/<-rpc - (select-keys [:name :chat-type :chat-name :public? :group-chat])))))) + (is (= {:chat-name chat-name + :chat-type constants/one-to-one-chat-type + :group-chat false + :name chat-name + :public? false} + (-> raw-notification + (assoc :type constants/activity-center-notification-type-one-to-one-chat) + store/<-rpc + (select-keys [:name :chat-type :chat-name :public? :group-chat])))))))