Compare commits
18
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a81151be3a | ||
|
|
1da39e064d | ||
|
|
3899368aa0 | ||
|
|
5ff1c8f1e4 | ||
|
|
7289940653 | ||
|
|
a253f8cedb | ||
|
|
daf52102ce | ||
|
|
fa20d4d9c3 | ||
|
|
dd26fcf42c | ||
|
|
8ac9cc08e1 | ||
|
|
c1230319e1 | ||
|
|
1e48442d67 | ||
|
|
94fbbbcb3c | ||
|
|
4dfd616583 | ||
|
|
85d00e47af | ||
|
|
438fd7a512 | ||
|
|
ee5f73f5ee | ||
|
|
b49c0ae58a |
@@ -1,4 +1,4 @@
|
||||
{ callPackage, lib, buildGoPackage
|
||||
{ callPackage, lib, buildGoPackage, pkgs
|
||||
, androidPkgs, openjdk, gomobile, xcodeWrapper, removeReferencesTo
|
||||
, go-bindata, mockgen, protobuf3_20, protoc-gen-go
|
||||
, meta
|
||||
@@ -15,6 +15,8 @@ let
|
||||
isIOS = platform == "ios";
|
||||
isAndroid = platform == "android";
|
||||
enforceXCodeAvailable = callPackage ./enforceXCodeAvailable.nix { };
|
||||
# Fixes fatal: not a git repository (or any of the parent directories): .git
|
||||
fakeGit = pkgs.writeScriptBin "git" "echo ${source.version}";
|
||||
|
||||
in buildGoPackage rec {
|
||||
pname = source.repo;
|
||||
@@ -29,7 +31,7 @@ in buildGoPackage rec {
|
||||
|
||||
extraSrcPaths = [ gomobile ];
|
||||
nativeBuildInputs = [
|
||||
gomobile removeReferencesTo go-bindata mockgen protoc-gen-go protobuf3_20
|
||||
gomobile removeReferencesTo go-bindata mockgen protoc-gen-go protobuf3_20 fakeGit
|
||||
] ++ optional isAndroid openjdk
|
||||
++ optional isIOS xcodeWrapper;
|
||||
|
||||
|
||||
@@ -253,15 +253,19 @@
|
||||
|
||||
(defn hash-typed-data
|
||||
"used for keycard"
|
||||
[data callback]
|
||||
(log/debug "[native-module] hash-typed-data")
|
||||
(.hashTypedData ^js (encryption) data callback))
|
||||
([data]
|
||||
(native-utils/promisify-native-module-call hash-typed-data data))
|
||||
([data callback]
|
||||
(log/debug "[native-module] hash-typed-data")
|
||||
(.hashTypedData ^js (encryption) data callback)))
|
||||
|
||||
(defn hash-typed-data-v4
|
||||
"used for keycard"
|
||||
[data callback]
|
||||
(log/debug "[native-module] hash-typed-data-v4")
|
||||
(.hashTypedDataV4 ^js (encryption) data callback))
|
||||
([data]
|
||||
(native-utils/promisify-native-module-call hash-typed-data-v4 data))
|
||||
([data callback]
|
||||
(log/debug "[native-module] hash-typed-data-v4")
|
||||
(.hashTypedDataV4 ^js (encryption) data callback)))
|
||||
|
||||
(defn send-transaction-with-signature
|
||||
"used for keycard"
|
||||
|
||||
@@ -30,7 +30,8 @@
|
||||
selected? (assoc :border-top-color (colors/alpha color 0.4)
|
||||
:border-end-color (colors/alpha color 0.4)
|
||||
:border-bottom-color (colors/alpha color 0.2)
|
||||
:border-start-color (colors/alpha color 0.2))
|
||||
:border-start-color (colors/alpha color 0.2)
|
||||
:border-color nil)
|
||||
(zero? idx) (assoc :margin-left -4))))
|
||||
|
||||
(defn color-circle
|
||||
|
||||
@@ -31,7 +31,8 @@
|
||||
[:scroll? {:optional true} [:maybe :boolean]]
|
||||
[:blur? {:optional true} [:maybe :boolean]]
|
||||
[:container-style {:optional true} [:maybe :map]]
|
||||
[:buttons-container-style {:optional true} [:maybe :map]]]]]
|
||||
[:buttons-container-style {:optional true} [:maybe :map]]
|
||||
[:buttons-style {:optional true} [:maybe :map]]]]]
|
||||
:any])
|
||||
|
||||
(def ^:private role-icon
|
||||
@@ -43,10 +44,9 @@
|
||||
(defn- view-internal
|
||||
[{:keys [actions description description-text description-top-text error-message role button-one-label
|
||||
button-two-label blur? button-one-props button-two-props scroll? container-style
|
||||
buttons-container-style context-tag-props]}]
|
||||
buttons-container-style buttons-style context-tag-props]}]
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
[rn/view
|
||||
{:style (merge (style/container scroll? blur? theme) container-style)}
|
||||
[rn/view {:style (merge (style/container scroll? blur? theme) container-style)}
|
||||
(when (= description :top-error)
|
||||
[rn/view {:style style/error-message}
|
||||
[icon/icon
|
||||
@@ -82,7 +82,7 @@
|
||||
[button/button
|
||||
(merge
|
||||
{:size 40
|
||||
:container-style style/button-container
|
||||
:container-style (merge style/button-container buttons-style)
|
||||
:background (when (or blur? scroll?) :blur)
|
||||
:theme theme
|
||||
:accessibility-label :button-two}
|
||||
@@ -91,7 +91,7 @@
|
||||
[button/button
|
||||
(merge
|
||||
{:size 40
|
||||
:container-style style/button-container
|
||||
:container-style (merge style/button-container buttons-style)
|
||||
:background (when (or blur? scroll?) :blur)
|
||||
:theme theme
|
||||
:accessibility-label :button-one}
|
||||
|
||||
@@ -21,13 +21,13 @@
|
||||
[{:keys [type on-press on-check disabled? checked? child]} customization-color theme]
|
||||
(if (= type :custom)
|
||||
child
|
||||
[rn/touchable-opacity
|
||||
{:on-press on-press}
|
||||
[rn/touchable-opacity {:on-press on-press}
|
||||
(case type
|
||||
:options
|
||||
[icons/icon :i/options
|
||||
{:size 20
|
||||
:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)}]
|
||||
|
||||
:checkbox
|
||||
[selectors/view
|
||||
{:type :checkbox
|
||||
@@ -36,6 +36,7 @@
|
||||
:accessibility-label :user-list-toggle-check
|
||||
:disabled? disabled?
|
||||
:on-change (when on-check on-check)}]
|
||||
|
||||
:close
|
||||
[text/text "not implemented"]
|
||||
[rn/view])]))
|
||||
|
||||
@@ -66,7 +66,8 @@
|
||||
button-label]])
|
||||
|
||||
(defn small-option-card
|
||||
[{:keys [variant title subtitle button-label image max-height on-press accessibility-label button-type]
|
||||
[{:keys [variant title subtitle button-label image max-height on-press accessibility-label
|
||||
button-type container-style]
|
||||
:or {variant :main accessibility-label :small-option-card}}]
|
||||
(let [main-variant? (= variant :main)
|
||||
card-component (if main-variant? main-variant icon-variant)
|
||||
@@ -74,7 +75,7 @@
|
||||
(not main-variant?) style/icon-variant-height
|
||||
max-height (min max-height style/main-variant-height)
|
||||
:else style/main-variant-height)]
|
||||
[rn/view {:style (style/card card-height)}
|
||||
[rn/view {:style (merge (style/card card-height) container-style)}
|
||||
[card-component
|
||||
{:title title
|
||||
:subtitle subtitle
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
:border-color (colors/theme-colors colors/neutral-20 dark-border theme)}))
|
||||
|
||||
(def text
|
||||
{:margin-left 8})
|
||||
{:flex 1
|
||||
:margin-left 8})
|
||||
|
||||
(def icon-container
|
||||
{:align-items :flex-end
|
||||
|
||||
@@ -265,16 +265,11 @@
|
||||
:sub-label nil
|
||||
:chevron? false}))
|
||||
|
||||
;; TODO(OmarBasem): Requires design input.
|
||||
(defn show-qr-entry
|
||||
[public-key]
|
||||
(entry {:icon :i/qr-code
|
||||
:label (i18n/label :t/show-qr)
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:universal-links/generate-profile-url
|
||||
{:public-key public-key
|
||||
:on-success #(rf/dispatch [:open-modal
|
||||
:share-contact])}]))
|
||||
:on-press #(rf/dispatch [:contacts/show-qr-code public-key])
|
||||
:danger? false
|
||||
:accessibility-label :show-qr-code
|
||||
:sub-label nil
|
||||
|
||||
@@ -73,10 +73,10 @@
|
||||
[{:keys [scroll-ref tabs selected-tab on-tab-change scroll-shared-value content customization-color]}]
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
[:<>
|
||||
[:f> banner-card-blur-layer scroll-shared-value
|
||||
[:f> banner-card-hiding-layer
|
||||
[banner-card-blur-layer scroll-shared-value
|
||||
[banner-card-hiding-layer
|
||||
(assoc content :scroll-shared-value scroll-shared-value :theme theme)]]
|
||||
[:f> banner-card-tabs-layer
|
||||
[banner-card-tabs-layer
|
||||
{:scroll-shared-value scroll-shared-value
|
||||
:selected-tab selected-tab
|
||||
:tabs tabs
|
||||
|
||||
@@ -213,13 +213,15 @@
|
||||
|
||||
(defn save-profile-url
|
||||
[{:keys [db]} [public-key url]]
|
||||
(when url
|
||||
{:db
|
||||
(cond-> db
|
||||
(get-in db [:contacts/contacts public-key])
|
||||
(assoc-in [:contacts/contacts public-key :universal-profile-url] url)
|
||||
(= public-key (get-in db [:profile/profile :public-key]))
|
||||
(assoc-in [:profile/profile :universal-profile-url] url))}))
|
||||
(let [contact-from-key (get-in db [:contacts/contacts public-key])
|
||||
profile-public-key? (= public-key (get-in db [:profile/profile :public-key]))]
|
||||
(when url
|
||||
{:db (cond-> db
|
||||
contact-from-key
|
||||
(assoc-in [:contacts/contacts public-key :universal-profile-url] url)
|
||||
|
||||
profile-public-key?
|
||||
(assoc-in [:profile/profile :universal-profile-url] url))})))
|
||||
|
||||
(schema/=> save-profile-url
|
||||
[:=>
|
||||
|
||||
@@ -129,5 +129,5 @@
|
||||
;; if you're using android simulator, I suggest set the env variable to "http://10.0.2.2:"
|
||||
(goog-define STATUS_BACKEND_SERVER_IMAGE_SERVER_URI_PREFIX "https://localhost:")
|
||||
|
||||
(def re-frisk-host (get-config :RE_FRISK_HOST "http://localhost"))
|
||||
(def re-frisk-host (get-config :RE_FRISK_HOST "localhost"))
|
||||
(def re-frisk-port (get-config :RE_FRISK_PORT "4567"))
|
||||
|
||||
@@ -221,10 +221,7 @@
|
||||
(def ^:const wallet-connect-eth-sign-typed-v4-method "eth_signTypedData_v4")
|
||||
(def ^:const wallet-connect-supported-methods
|
||||
#{wallet-connect-personal-sign-method
|
||||
wallet-connect-eth-sign-method
|
||||
wallet-connect-eth-send-transaction-method
|
||||
;; NOTE: disabled, as we have no clear use cases for it and other wallets don't support it
|
||||
;; wallet-connect-eth-sign-transaction-method
|
||||
wallet-connect-eth-sign-typed-method
|
||||
wallet-connect-eth-sign-typed-v4-method})
|
||||
(def ^:const wallet-connect-supported-events #{"accountsChanged" "chainChanged"})
|
||||
@@ -237,11 +234,9 @@
|
||||
(def ^:const wallet-connect-message-signing-methods
|
||||
#{wallet-connect-personal-sign-method
|
||||
wallet-connect-eth-sign-typed-method
|
||||
wallet-connect-eth-sign-method
|
||||
wallet-connect-eth-sign-typed-v4-method})
|
||||
(def ^:const wallet-connect-transaction-methods
|
||||
#{wallet-connect-eth-send-transaction-method
|
||||
wallet-connect-eth-sign-transaction-method})
|
||||
#{wallet-connect-eth-send-transaction-method})
|
||||
|
||||
(def ^:const transaction-pending-type-wallet-connect-transfer "WalletConnectTransfer")
|
||||
|
||||
|
||||
@@ -151,3 +151,12 @@
|
||||
error]]]})
|
||||
|
||||
(rf/reg-event-fx :contacts/update-nickname-error update-nickname-error)
|
||||
|
||||
(rf/reg-event-fx
|
||||
:contacts/show-qr-code
|
||||
(fn [{db :db} [public-key]]
|
||||
{:db (assoc db :contacts/identity public-key)
|
||||
:fx [[:dispatch
|
||||
[:universal-links/generate-profile-url
|
||||
{:public-key public-key
|
||||
:on-success #(rf/dispatch [:open-modal :share-contact])}]]]}))
|
||||
|
||||
@@ -114,13 +114,17 @@
|
||||
{:scroll-input (oops/oget % "nativeEvent.contentOffset.y")
|
||||
:shared-value scroll-shared-value})}])))
|
||||
|
||||
(defn- on-new-message-press
|
||||
[]
|
||||
(let [main-event [:show-bottom-sheet {:content chat.actions.view/new-chat}]]
|
||||
(rf/dispatch [:profile/check-profile-update-prompt main-event])))
|
||||
|
||||
(defn- banner-data
|
||||
[profile-link]
|
||||
{:title-props
|
||||
{:beta? true
|
||||
:label (i18n/label :t/messages)
|
||||
:handler #(rf/dispatch
|
||||
[:show-bottom-sheet {:content chat.actions.view/new-chat}])
|
||||
:handler on-new-message-press
|
||||
:accessibility-label :new-chat-button}
|
||||
:card-props
|
||||
{:on-press #(rf/dispatch [:open-share {:options {:url profile-link}}])
|
||||
|
||||
@@ -159,7 +159,9 @@
|
||||
[content]
|
||||
(reduce (fn [acc e]
|
||||
(conj acc (resolve-group-system-message e)))
|
||||
[quo/text]
|
||||
[rn/view
|
||||
{:style {:flex-direction :row
|
||||
:flex-wrap :wrap}}]
|
||||
(:parsed-text content)))
|
||||
|
||||
(defn group-system-message
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
(ns status-im.contexts.keycard.backup.events
|
||||
(:require [utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
(rf/reg-event-fx :keycard/backup.generate-and-load-key
|
||||
(fn [{:keys [db]}]
|
||||
(let [{:keys [masked-phrase pin]} (get-in db [:keycard :backup])]
|
||||
{:fx [[:effects.keycard/generate-and-load-key
|
||||
{:mnemonic (security/safe-unmask-data masked-phrase)
|
||||
:pin pin
|
||||
:on-success (fn []
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch [:navigate-back])
|
||||
(rf/dispatch [:open-modal :screen/keycard.backup.success]))
|
||||
:on-failure #(rf/dispatch [:keycard/on-action-with-pin-error %])}]]})))
|
||||
|
||||
(defn- ready-to-add-not-empty
|
||||
[error]
|
||||
(rf/dispatch [:navigate-back])
|
||||
(if (= error :keycard/error.not-keycard)
|
||||
(rf/dispatch [:keycard/on-application-info-error error])
|
||||
(do
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch [:open-modal :screen/keycard.backup.not-empty
|
||||
{:on-press #(rf/dispatch [:keycard/backup.ready-to-add-connect])}]))))
|
||||
|
||||
(rf/reg-event-fx :keycard/backup.ready-to-add-connect
|
||||
(fn [_]
|
||||
{:fx [[:dispatch
|
||||
[:keycard/connect
|
||||
{:on-error
|
||||
(fn [error]
|
||||
(if (= error :keycard/error.keycard-blank)
|
||||
(rf/dispatch [:keycard/backup.generate-and-load-key])
|
||||
(ready-to-add-not-empty error)))}]]]}))
|
||||
|
||||
(defn- scan-empty-card-not-empty
|
||||
[error]
|
||||
(rf/dispatch [:navigate-back])
|
||||
(if (= error :keycard/error.not-keycard)
|
||||
(rf/dispatch [:keycard/on-application-info-error error])
|
||||
(do
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch [:open-modal :screen/keycard.backup.not-empty
|
||||
{:on-press #(rf/dispatch [:keycard/backup.scan-empty-card])}]))))
|
||||
|
||||
(rf/reg-event-fx :keycard/backup.scan-empty-card
|
||||
(fn [_]
|
||||
{:fx [[:dispatch
|
||||
[:keycard/connect
|
||||
{:on-error
|
||||
(fn [error]
|
||||
(if (= error :keycard/error.keycard-blank)
|
||||
(do
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch [:keycard/backup.create-or-enter-pin]))
|
||||
(scan-empty-card-not-empty error)))}]]]}))
|
||||
|
||||
(rf/reg-event-fx :keycard/backup.save-pin
|
||||
(fn [{:keys [db]} [pin]]
|
||||
{:db (assoc-in db [:keycard :backup :pin] pin)}))
|
||||
|
||||
(defn- save-pin-and-navigate-to-phrase
|
||||
[pin]
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch [:navigate-back])
|
||||
(rf/dispatch [:keycard/backup.save-pin pin])
|
||||
(rf/dispatch
|
||||
[:open-modal :screen/use-recovery-phrase-dark
|
||||
{:on-success #(rf/dispatch [:keycard/backup.phrase-entered %])}]))
|
||||
|
||||
(defn- verify-entered-pin-and-continue
|
||||
[pin]
|
||||
(rf/dispatch
|
||||
[:keycard/connect
|
||||
{:on-error
|
||||
(fn [error]
|
||||
(if (= error :keycard/error.keycard-blank)
|
||||
(rf/dispatch
|
||||
[:keycard/verify-pin
|
||||
{:pin pin
|
||||
:on-success #(save-pin-and-navigate-to-phrase pin)
|
||||
:on-failure #(rf/dispatch [:keycard/on-action-with-pin-error %])}])
|
||||
(rf/dispatch [:keycard/on-application-info-error error])))}]))
|
||||
|
||||
(declare init-card-not-empty)
|
||||
|
||||
(defn- init-card-with-pin-and-continue
|
||||
[pin]
|
||||
(rf/dispatch
|
||||
[:keycard/connect
|
||||
{:on-error
|
||||
(fn [error]
|
||||
(if (= error :keycard/error.keycard-blank)
|
||||
(rf/dispatch
|
||||
[:keycard/init-card
|
||||
{:pin pin
|
||||
:on-success #(rf/dispatch
|
||||
[:keycard/get-application-info
|
||||
{:on-error
|
||||
(fn [error]
|
||||
(if (= error :keycard/error.keycard-blank)
|
||||
(save-pin-and-navigate-to-phrase pin)
|
||||
(init-card-not-empty pin error)))}])}])
|
||||
(init-card-not-empty pin error)))}]))
|
||||
|
||||
(defn- init-card-not-empty
|
||||
[pin error]
|
||||
(rf/dispatch [:navigate-back])
|
||||
(if (= error :keycard/error.not-keycard)
|
||||
(rf/dispatch [:keycard/on-application-info-error error])
|
||||
(do
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch [:open-modal :screen/keycard.backup.not-empty
|
||||
{:on-press #(init-card-with-pin-and-continue pin)}]))))
|
||||
|
||||
(rf/reg-event-fx :keycard/backup.create-or-enter-pin
|
||||
(fn [{:keys [db]}]
|
||||
(let [{:keys [initialized?]} (get-in db [:keycard :application-info])]
|
||||
{:fx [[:dispatch [:navigate-back]]
|
||||
(if initialized?
|
||||
[:dispatch
|
||||
[:open-modal :screen/keycard.pin.enter
|
||||
{:on-complete verify-entered-pin-and-continue}]]
|
||||
[:dispatch
|
||||
[:open-modal :screen/keycard.pin.create
|
||||
{:on-complete init-card-with-pin-and-continue}]])]})))
|
||||
|
||||
(rf/reg-event-fx :keycard/backup.phrase-entered
|
||||
(fn [{:keys [db]} [{:keys [phrase]}]]
|
||||
{:db (assoc-in db [:keycard :backup :masked-phrase] phrase)
|
||||
:fx [[:dispatch [:navigate-back]]
|
||||
[:dispatch [:open-modal :screen/keycard.backup.ready-to-add]]]}))
|
||||
@@ -0,0 +1,96 @@
|
||||
(ns status-im.contexts.keycard.backup.view
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[status-im.common.resources :as resources]
|
||||
[status-im.contexts.keycard.common.view :as common.view]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn ready-to-add
|
||||
[]
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:icon-name :i/close
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/ready-add-keypair-keycard)}]
|
||||
[rn/view {:style {:flex 1 :align-items :center :justify-content :center}}
|
||||
[rn/image
|
||||
{:resize-mode :contain
|
||||
:source (resources/get-image :keycard-migration)}]]
|
||||
[common.view/tips]
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-label (i18n/label :t/scan-keycard)
|
||||
:button-one-props {:on-press #(rf/dispatch [:keycard/backup.ready-to-add-connect])}}]])
|
||||
|
||||
(defn success-view
|
||||
[]
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:icon-name :i/close
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/backup-keycard-created)}]
|
||||
[rn/view {:style {:flex 1}}]
|
||||
[rn/view {:style {:padding-horizontal 20}}
|
||||
[quo/button {:on-press events-helper/navigate-back}
|
||||
(i18n/label :t/done)]]])
|
||||
|
||||
(defn not-empty-view
|
||||
[]
|
||||
(let [{:keys [on-press]} (rf/sub [:get-screen-params])]
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:icon-name :i/close
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/keycard-not-empty)
|
||||
:description :text
|
||||
:description-text (i18n/label :t/scan-empty-keycard)}]
|
||||
[rn/view {:style {:flex 1}}]
|
||||
[common.view/tips]
|
||||
[rn/view {:style {:padding-horizontal 20}}
|
||||
[quo/button {:on-press on-press}
|
||||
(i18n/label :t/try-again)]]]))
|
||||
|
||||
(defn scan-empty
|
||||
[]
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:icon-name :i/close
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/scan-empty-keycard)
|
||||
:description :text
|
||||
:description-text (i18n/label :t/backup-empty-keycard-only)}]
|
||||
[rn/view {:style {:flex 1 :align-items :center :justify-content :center}}
|
||||
[rn/image
|
||||
{:resize-mode :contain
|
||||
:source (resources/get-image :check-your-keycard)}]]
|
||||
[common.view/tips]
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-label (i18n/label :t/ready-to-scan)
|
||||
:button-one-props {:on-press #(rf/dispatch [:keycard/backup.scan-empty-card])}}]])
|
||||
|
||||
(defn sheet
|
||||
[{:keys [on-continue]}]
|
||||
(let [customization-color (rf/sub [:profile/customization-color])]
|
||||
[:<>
|
||||
[quo/drawer-top {:title (i18n/label :t/create-backup-keycard)}]
|
||||
[quo/text
|
||||
{:style {:padding-horizontal 20
|
||||
:padding-vertical 8}}
|
||||
(i18n/label :t/backup-keycard-instructions)]
|
||||
[quo/bottom-actions
|
||||
{:actions :two-actions
|
||||
:button-one-label (i18n/label :t/continue)
|
||||
:button-one-props {:customization-color customization-color
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(on-continue))}
|
||||
:button-two-label (i18n/label :t/cancel)
|
||||
:button-two-props {:type :grey
|
||||
:on-press #(rf/dispatch [:hide-bottom-sheet])}}]]))
|
||||
@@ -0,0 +1,25 @@
|
||||
(ns status-im.contexts.keycard.check.events
|
||||
(:require [utils.re-frame :as rf]))
|
||||
|
||||
(rf/reg-event-fx :keycard/check-empty-card
|
||||
(fn [{:keys [db]}]
|
||||
(let [keycard-profile? (not (nil? (get-in db [:profile/profile :keycard-pairing])))]
|
||||
{:fx [[:dispatch
|
||||
[:keycard/connect
|
||||
{:key-uid (get-in db [:profile/profile :key-uid])
|
||||
:on-success
|
||||
(fn []
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch [:navigate-back])
|
||||
(if keycard-profile?
|
||||
(rf/dispatch [:open-modal :screen/keycard.manage.profile-keys])
|
||||
(rf/dispatch [:open-modal :screen/keycard.migrate.profile-keys])))
|
||||
:on-error
|
||||
(fn [error]
|
||||
(rf/dispatch [:navigate-back])
|
||||
(if (and (= error :keycard/error.keycard-blank)
|
||||
(not keycard-profile?))
|
||||
(do
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch [:open-modal :screen/keycard.empty]))
|
||||
(rf/dispatch [:keycard/on-application-info-error error])))}]]]})))
|
||||
@@ -3,16 +3,40 @@
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[status-im.common.resources :as resources]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.keycard.common.view :as common.view]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- keycard-documentation
|
||||
[]
|
||||
[quo/documentation-drawers
|
||||
{:title (i18n/label :t/keycard)
|
||||
:shell? true}
|
||||
[rn/view
|
||||
[quo/text {:size :paragraph-2}
|
||||
(i18n/label :t/keycard-documentation)]
|
||||
[quo/button
|
||||
{:size 40
|
||||
:type :primary
|
||||
:container-style {:margin-top 24 :margin-bottom 12}
|
||||
:background :blur
|
||||
:icon-right :i/external
|
||||
:on-press #(rf/dispatch [:browser.ui/open-url constants/get-keycard-url])
|
||||
:accessibility-label :get-keycard}
|
||||
(i18n/label :t/buy-keycard)]]])
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [{:keys [on-press]} (rf/sub [:get-screen-params])]
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:icon-name :i/arrow-left
|
||||
:on-press events-helper/navigate-back}]
|
||||
{:icon-name :i/arrow-left
|
||||
:on-press events-helper/navigate-back
|
||||
:right-side [{:icon-name :i/info
|
||||
:on-press #(rf/dispatch [:show-bottom-sheet
|
||||
{:content keycard-documentation
|
||||
:shell? true}])}]}]
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/check-keycard)
|
||||
:description :text
|
||||
@@ -21,9 +45,7 @@
|
||||
[rn/image
|
||||
{:resize-mode :contain
|
||||
:source (resources/get-image :check-your-keycard)}]]
|
||||
[quo/divider-label (i18n/label :t/tips-scan-keycard)]
|
||||
[quo/markdown-list {:description (i18n/label :t/remove-phone-case)}]
|
||||
[quo/markdown-list {:description (i18n/label :t/keep-card-steady)}]
|
||||
[common.view/tips]
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-label (i18n/label :t/ready-to-scan)
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
(ns status-im.contexts.keycard.common.view
|
||||
(:require [quo.core :as quo]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(defn tips
|
||||
[]
|
||||
[:<>
|
||||
[quo/divider-label (i18n/label :t/tips-scan-keycard)]
|
||||
[quo/markdown-list {:description (i18n/label :t/remove-phone-case)}]
|
||||
[quo/markdown-list {:description (i18n/label :t/keep-card-steady)}]])
|
||||
@@ -90,7 +90,7 @@
|
||||
(cond
|
||||
|
||||
(not initialized?)
|
||||
{:fx [[:keycard/init-card
|
||||
{:fx [[:effects.keycard/init-card
|
||||
{:pin pin
|
||||
:on-success get-application-info-and-continue}]]}
|
||||
|
||||
@@ -106,3 +106,10 @@
|
||||
{:pin pin
|
||||
:on-success #(rf/dispatch [:keycard.login/recover-profile-and-login %])
|
||||
:on-failure #(rf/dispatch [:keycard/on-action-with-pin-error %])}]]}))))
|
||||
|
||||
(rf/reg-event-fx :keycard/create.seed-phrase-entered
|
||||
(fn [{:keys [db]} [key-uid masked-seed-phrase]]
|
||||
(if (contains? (:profile/profiles-overview db) key-uid)
|
||||
{:fx [[:dispatch [:onboarding/multiaccount-already-exists key-uid]]]}
|
||||
{:db (assoc-in db [:keycard :create :masked-phrase] masked-seed-phrase)
|
||||
:fx [[:dispatch [:keycard/create.create-or-enter-pin]]]})))
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
[status-im.common.resources :as resources]
|
||||
[status-im.config :as config]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.keycard.common.view :as common.view]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
@@ -37,9 +38,7 @@
|
||||
:image (resources/get-image :use-keycard)
|
||||
:on-press #(rf/dispatch [:browser.ui/open-url constants/get-keycard-url])}]]
|
||||
[rn/view {:style {:flex 1}}]
|
||||
[quo/divider-label (i18n/label :t/tips-scan-keycard)]
|
||||
[quo/markdown-list {:description (i18n/label :t/remove-phone-case)}]
|
||||
[quo/markdown-list {:description (i18n/label :t/keep-card-steady)}]])
|
||||
[common.view/tips]])
|
||||
|
||||
(defn ready-to-add
|
||||
[]
|
||||
@@ -58,9 +57,7 @@
|
||||
{:resize-mode :contain
|
||||
:style {:flex 1 :align-self :center :margin-vertical 37}
|
||||
:source (resources/get-image :add-key-to-keycard)}]
|
||||
[quo/divider-label (i18n/label :t/tips-scan-keycard)]
|
||||
[quo/markdown-list {:description (i18n/label :t/remove-phone-case)}]
|
||||
[quo/markdown-list {:description (i18n/label :t/keep-card-steady)}]
|
||||
[common.view/tips]
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-label (i18n/label :t/scan-keycard)
|
||||
|
||||
@@ -56,6 +56,10 @@
|
||||
(fn [args]
|
||||
(keycard/factory-reset (keycard.utils/wrap-handlers args))))
|
||||
|
||||
(rf/reg-fx :effects.keycard/verify-pin
|
||||
(fn [args]
|
||||
(keycard/verify-pin (keycard.utils/wrap-handlers args))))
|
||||
|
||||
(rf/reg-fx :effects.keycard/sign
|
||||
(fn [args]
|
||||
(-> (keycard/sign args)
|
||||
@@ -75,7 +79,7 @@
|
||||
(promesa/then on-success)
|
||||
(promesa/catch (keycard.utils/get-on-failure args)))))
|
||||
|
||||
(rf/reg-fx :keycard/init-card
|
||||
(rf/reg-fx :effects.keycard/init-card
|
||||
(fn [args]
|
||||
(keycard/init-card (keycard.utils/wrap-handlers args))))
|
||||
|
||||
|
||||
@@ -17,20 +17,27 @@
|
||||
{:title (i18n/label :t/keycard-empty)
|
||||
:description :text
|
||||
:description-text (i18n/label :t/what-to-do)}]
|
||||
[rn/view {:style {:padding-horizontal 28 :padding-top 20}}
|
||||
[quo/small-option-card
|
||||
{:variant :main
|
||||
:title (i18n/label :t/create-new-profile)
|
||||
:subtitle (i18n/label :t/new-key-pair-keycard)
|
||||
:button-label (i18n/label :t/lets-go)
|
||||
:accessibility-label :create-new-profile-keycard
|
||||
:image (resources/get-image :keycard-buy)
|
||||
:button-type :primary
|
||||
:on-press #(rf/dispatch [:keycard/create.get-phrase])}]]
|
||||
[quo/information-box
|
||||
{:type :default
|
||||
:style {:margin-top 32 :margin-horizontal 28}}
|
||||
(i18n/label :t/add-key-pair-desktop)]])
|
||||
[quo/small-option-card
|
||||
{:variant :main
|
||||
:title (i18n/label :t/create-new-profile)
|
||||
:subtitle (i18n/label :t/new-key-pair-keycard)
|
||||
:button-label (i18n/label :t/lets-go)
|
||||
:accessibility-label :create-new-profile-keycard
|
||||
:container-style {:margin-horizontal 20 :margin-top 8}
|
||||
:image (resources/get-image :keycard-buy)
|
||||
:button-type :primary
|
||||
:on-press #(rf/dispatch [:keycard/create.get-phrase])}]
|
||||
[quo/small-option-card
|
||||
{:variant :icon
|
||||
:title (i18n/label :t/import-recovery-phrase-to-keycard)
|
||||
:subtitle (i18n/label :t/store-key-pair-on-keycard)
|
||||
:accessibility-label :import-recovery-phrase-to-keycard
|
||||
:container-style {:margin 20}
|
||||
:image (resources/get-image :use-keycard)
|
||||
:on-press #(rf/dispatch [:open-modal :screen/use-recovery-phrase-dark
|
||||
{:on-success (fn [{:keys [key-uid phrase]}]
|
||||
(rf/dispatch [:keycard/create.seed-phrase-entered
|
||||
key-uid phrase]))}])}]])
|
||||
|
||||
(defn view
|
||||
[]
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[status-im.contexts.keycard.backup.view :as backup.view]
|
||||
[status-im.contexts.keycard.factory-reset.view :as factory-reset]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
@@ -32,17 +33,31 @@
|
||||
:description-text description}]
|
||||
[rn/view {:style {:margin-horizontal 20}}
|
||||
[quo/keycard {:holder-name ""}]
|
||||
(when (not= :keycard/error.keycard-blank error)
|
||||
[:<>
|
||||
[quo/section-label
|
||||
{:section (i18n/label :t/what-you-can-do) :container-style {:padding-vertical 8}}]
|
||||
[quo/settings-item
|
||||
{:title (i18n/label :t/factory-reset)
|
||||
:image :icon
|
||||
:image-props :i/placeholder
|
||||
:action :arrow
|
||||
:description :text
|
||||
:description-props {:text (i18n/label :t/remove-keycard-content)}
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content factory-reset/sheet}]))}]])]]))
|
||||
[quo/section-label
|
||||
{:section (i18n/label :t/what-you-can-do) :container-style {:padding-vertical 8}}]
|
||||
(if (= error :keycard/error.keycard-blank)
|
||||
[quo/settings-item
|
||||
{:title (i18n/label :t/use-backup-keycard)
|
||||
:image :icon
|
||||
:image-props :i/placeholder
|
||||
:action :arrow
|
||||
:description :text
|
||||
:description-props {:text (i18n/label :t/create-backup-profile-keycard)}
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content
|
||||
(fn []
|
||||
[backup.view/sheet
|
||||
{:on-continue
|
||||
(rf/dispatch
|
||||
[:keycard/backup.create-or-enter-pin])}])}]))}]
|
||||
[quo/settings-item
|
||||
{:title (i18n/label :t/factory-reset)
|
||||
:image :icon
|
||||
:image-props :i/placeholder
|
||||
:action :arrow
|
||||
:description :text
|
||||
:description-props {:text (i18n/label :t/remove-keycard-content)}
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content factory-reset/sheet}]))}])]]))
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
(ns status-im.contexts.keycard.events
|
||||
(:require [re-frame.core :as rf]
|
||||
status-im.contexts.keycard.backup.events
|
||||
status-im.contexts.keycard.check.events
|
||||
status-im.contexts.keycard.create.events
|
||||
status-im.contexts.keycard.login.events
|
||||
status-im.contexts.keycard.migrate.events
|
||||
@@ -56,6 +58,10 @@
|
||||
[:keycard/on-application-info-error
|
||||
:keycard/error.keycard-locked]])]}))))
|
||||
|
||||
(rf/reg-event-fx :keycard/init-card
|
||||
(fn [_ [data]]
|
||||
{:effects.keycard/init-card data}))
|
||||
|
||||
(rf/reg-event-fx :keycard/get-keys
|
||||
(fn [_ [data]]
|
||||
{:effects.keycard/get-keys data}))
|
||||
@@ -72,6 +78,10 @@
|
||||
(fn [_ [data]]
|
||||
{:effects.keycard/factory-reset data}))
|
||||
|
||||
(rf/reg-event-fx :keycard/verify-pin
|
||||
(fn [_ [data]]
|
||||
{:effects.keycard/verify-pin data}))
|
||||
|
||||
(rf/reg-event-fx :keycard/connect-derive-address-and-add-account
|
||||
(fn [_ [{:keys [pin derivation-path key-uid account-preferences]}]]
|
||||
{:fx [[:dispatch
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
(ns status-im.contexts.keycard.manage.profile-keys.view
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[status-im.contexts.keycard.backup.view :as backup.view]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- backup-sheet
|
||||
[]
|
||||
[backup.view/sheet
|
||||
{:on-continue
|
||||
(fn []
|
||||
(rf/dispatch [:navigate-back])
|
||||
(rf/dispatch
|
||||
[:open-modal :screen/keycard.backup.scan-empty]))}])
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [profile-name (rf/sub [:profile/name])]
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:icon-name :i/close
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top
|
||||
{:title profile-name}]
|
||||
[rn/view {:style {:margin-horizontal 20}}
|
||||
[rn/view {:style {:padding-top 8 :padding-bottom 20}}
|
||||
[quo/keycard {:holder-name ""}]]
|
||||
[quo/section-label
|
||||
{:section (i18n/label :t/what-you-can-do) :container-style {:padding-vertical 8}}]
|
||||
[quo/settings-item
|
||||
{:title (i18n/label :t/backup-keycard)
|
||||
:image :icon
|
||||
:image-props :i/profile
|
||||
:action :arrow
|
||||
:description :text
|
||||
:description-props {:text (i18n/label :t/create-backup-profile-keycard)}
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:show-bottom-sheet {:content backup-sheet}]))}]]]))
|
||||
@@ -3,23 +3,6 @@
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
(rf/reg-event-fx :keycard/migration.check-empty-card
|
||||
(fn [{:keys [db]}]
|
||||
{:fx [[:dispatch
|
||||
[:keycard/connect
|
||||
{:key-uid (get-in db [:profile/profile :key-uid])
|
||||
:on-success
|
||||
(fn []
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch [:open-modal :screen/keycard.profile-keys]))
|
||||
:on-error
|
||||
(fn [error]
|
||||
(if (= error :keycard/error.keycard-blank)
|
||||
(do
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch [:open-modal :screen/keycard.empty]))
|
||||
(rf/dispatch [:keycard/on-application-info-error error])))}]]]}))
|
||||
|
||||
(defn get-application-info-and-continue
|
||||
[key-uid]
|
||||
(rf/dispatch [:keycard/get-application-info
|
||||
@@ -40,7 +23,7 @@
|
||||
(cond
|
||||
|
||||
(not initialized?)
|
||||
{:fx [[:keycard/init-card
|
||||
{:fx [[:effects.keycard/init-card
|
||||
{:pin pin
|
||||
:on-success #(get-application-info-and-continue key-uid)}]]}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[status-im.common.resources :as resources]
|
||||
[status-im.contexts.keycard.common.view :as common.view]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
@@ -26,9 +27,7 @@
|
||||
[rn/image
|
||||
{:resize-mode :contain
|
||||
:source (resources/get-image :keycard-migration)}]]
|
||||
[quo/divider-label (i18n/label :t/tips-scan-keycard)]
|
||||
[quo/markdown-list {:description (i18n/label :t/remove-phone-case)}]
|
||||
[quo/markdown-list {:description (i18n/label :t/keep-card-steady)}]
|
||||
[common.view/tips]
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-label (if initialized? (i18n/label :t/enter-keycard-pin) (i18n/label :t/scan-keycard))
|
||||
|
||||
@@ -76,3 +76,16 @@
|
||||
args
|
||||
:on-success (get-on-success args)
|
||||
:on-failure (get-on-failure args)))
|
||||
|
||||
(defn keycard-address?
|
||||
[keypairs address]
|
||||
(let [find-keycard-keypair (fn [kps] (some #(when-not (empty? (:keycards %)) %) kps))
|
||||
keypair-addresses (fn [kp]
|
||||
(->> (:accounts kp)
|
||||
(map :address)
|
||||
set))]
|
||||
(-> keypairs
|
||||
vals
|
||||
find-keycard-keypair
|
||||
keypair-addresses
|
||||
(contains? (string/lower-case address)))))
|
||||
|
||||
@@ -107,6 +107,19 @@
|
||||
[:navigate-to-within-stack [:screen/onboarding.enable-biometrics from-screen]]
|
||||
[:onboarding/create-account-and-login])]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:onboarding/multiaccount-already-exists
|
||||
(fn [_ [key-uid]]
|
||||
{:fx [[:effects.utils/show-confirmation
|
||||
{:title (i18n/label :t/multiaccount-exists-title)
|
||||
:content (i18n/label :t/multiaccount-exists-content)
|
||||
:confirm-button-text (i18n/label :t/unlock)
|
||||
:on-accept (fn []
|
||||
(re-frame/dispatch [:pop-to-root :screen/profile.profiles])
|
||||
;; Note - Profile selection is not working
|
||||
(re-frame/dispatch [:profile/profile-selected key-uid]))
|
||||
:on-cancel #(re-frame/dispatch [:pop-to-root :screen/profile.profiles])}]]}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:onboarding/seed-phrase-validated
|
||||
(fn [{:keys [db]} [seed-phrase key-uid]]
|
||||
@@ -115,14 +128,7 @@
|
||||
:onboarding/navigated-to-enter-seed-phrase-from-screen
|
||||
:screen/onboarding.create-profile)]
|
||||
(if (contains? (:profile/profiles-overview db) key-uid)
|
||||
{:fx [[:effects.utils/show-confirmation
|
||||
{:title (i18n/label :t/multiaccount-exists-title)
|
||||
:content (i18n/label :t/multiaccount-exists-content)
|
||||
:confirm-button-text (i18n/label :t/unlock)
|
||||
:on-accept (fn []
|
||||
(re-frame/dispatch [:pop-to-root :screen/profile.profiles])
|
||||
(re-frame/dispatch [:profile/profile-selected key-uid]))
|
||||
:on-cancel #(re-frame/dispatch [:pop-to-root :multiaccounts])}]]}
|
||||
{:fx [[:dispatch [:onboarding/multiaccount-already-exists key-uid]]]}
|
||||
{:db (-> db
|
||||
(assoc-in [:onboarding/profile :seed-phrase] seed-phrase)
|
||||
(assoc-in [:onboarding/profile :key-uid] key-uid)
|
||||
|
||||
@@ -52,7 +52,9 @@
|
||||
[quo/drawer-top
|
||||
{:type :context-tag
|
||||
:context-tag-type :default
|
||||
:title (i18n/label :t/add-nickname-title)
|
||||
:title (if has-nickname?
|
||||
(i18n/label :t/edit-nickname)
|
||||
(i18n/label :t/add-nickname-title))
|
||||
:full-name full-name
|
||||
:profile-picture profile-picture
|
||||
:customization-color customization-color}]
|
||||
|
||||
@@ -14,15 +14,14 @@
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn on-contact-request
|
||||
(defn on-send-contact-request
|
||||
[]
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content (fn [] [contact-request/view])}]))
|
||||
(let [main-event [:show-bottom-sheet {:content contact-request/view}]]
|
||||
(rf/dispatch [:profile/check-profile-update-prompt main-event])))
|
||||
|
||||
(defn on-contact-review
|
||||
[]
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content (fn [] [contact-review/view])}]))
|
||||
(rf/dispatch [:show-bottom-sheet {:content contact-review/view}]))
|
||||
|
||||
(defn view
|
||||
[{:keys [scroll-y]}]
|
||||
@@ -34,27 +33,27 @@
|
||||
profile-picture (profile.utils/photo contact)
|
||||
online? (rf/sub [:visibility-status-updates/online? public-key])
|
||||
theme (quo.theme/use-theme)
|
||||
contact-status (rn/use-memo (fn []
|
||||
(cond
|
||||
(= contact-request-state
|
||||
constants/contact-request-state-mutual) :contact
|
||||
blocked? :blocked
|
||||
:else nil))
|
||||
[blocked? contact-request-state])
|
||||
on-start-chat (rn/use-callback #(rf/dispatch [:chat.ui/start-chat
|
||||
public-key
|
||||
ens-name])
|
||||
[ens-name public-key])
|
||||
on-unblock-press (rn/use-callback (fn []
|
||||
(rf/dispatch [:contact/unblock-contact
|
||||
public-key])
|
||||
(rf/dispatch [:toasts/upsert
|
||||
{:id :user-unblocked
|
||||
:type :positive
|
||||
:text (i18n/label :t/user-unblocked
|
||||
{:username
|
||||
full-name})}]))
|
||||
[public-key full-name])]
|
||||
contact-status (rn/use-memo
|
||||
(fn []
|
||||
(cond
|
||||
(= contact-request-state
|
||||
constants/contact-request-state-mutual) :contact
|
||||
blocked? :blocked
|
||||
:else nil))
|
||||
[blocked? contact-request-state])
|
||||
on-start-chat (rn/use-callback
|
||||
#(rf/dispatch [:chat.ui/start-chat public-key ens-name])
|
||||
[ens-name public-key])
|
||||
on-unblock-press (rn/use-callback
|
||||
(fn []
|
||||
(rf/dispatch [:contact/unblock-contact
|
||||
public-key])
|
||||
(rf/dispatch [:toasts/upsert
|
||||
{:id :user-unblocked
|
||||
:type :positive
|
||||
:text (i18n/label :t/user-unblocked
|
||||
{:username full-name})}]))
|
||||
[public-key full-name])]
|
||||
[rn/view {:style style/header-container}
|
||||
[rn/view {:style style/header-top-wrapper}
|
||||
[rn/view {:style style/avatar-wrapper}
|
||||
@@ -93,14 +92,12 @@
|
||||
|
||||
(cond
|
||||
(and (not blocked?)
|
||||
(or
|
||||
(not contact-request-state)
|
||||
(= contact-request-state constants/contact-request-state-none)
|
||||
(= contact-request-state constants/contact-request-state-dismissed)))
|
||||
|
||||
(or (not contact-request-state)
|
||||
(= contact-request-state constants/contact-request-state-none)
|
||||
(= contact-request-state constants/contact-request-state-dismissed)))
|
||||
[quo/button
|
||||
{:container-style style/button-wrapper
|
||||
:on-press on-contact-request
|
||||
:on-press on-send-contact-request
|
||||
:customization-color customization-color
|
||||
:icon-left :i/add-user}
|
||||
(i18n/label :t/send-contact-request)]
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[status-im.common.qr-codes.view :as qr-codes]
|
||||
[status-im.contexts.profile.contact.share.style :as style]
|
||||
[status-im.contexts.profile.utils :as profile.utils]
|
||||
@@ -9,32 +10,32 @@
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn navigation-back [] (rf/dispatch [:navigate-back]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [{:keys [universal-profile-url customization-color]
|
||||
:as profile} (rf/sub [:contacts/current-contact])
|
||||
abbreviated-url (rn/use-memo (fn []
|
||||
(address/get-abbreviated-profile-url universal-profile-url))
|
||||
[universal-profile-url])
|
||||
on-share-press (rn/use-callback #(rf/dispatch [:open-share
|
||||
{:options {:message universal-profile-url}}])
|
||||
[universal-profile-url])
|
||||
on-copy-press (rn/use-callback (fn []
|
||||
(rf/dispatch [:share/copy-text-and-show-toast
|
||||
{:text-to-copy universal-profile-url
|
||||
:post-copy-message
|
||||
(i18n/label
|
||||
:t/link-to-profile-copied)}]))
|
||||
[universal-profile-url])]
|
||||
abbreviated-url (rn/use-memo
|
||||
(fn []
|
||||
(address/get-abbreviated-profile-url universal-profile-url))
|
||||
[universal-profile-url])
|
||||
on-share-press (rn/use-callback
|
||||
#(rf/dispatch [:open-share
|
||||
{:options {:message universal-profile-url}}])
|
||||
[universal-profile-url])
|
||||
on-copy-press (rn/use-callback
|
||||
(fn []
|
||||
(rf/dispatch
|
||||
[:share/copy-text-and-show-toast
|
||||
{:text-to-copy universal-profile-url
|
||||
:post-copy-message (i18n/label :t/link-to-profile-copied)}]))
|
||||
[universal-profile-url])]
|
||||
[quo/overlay {:type :shell}
|
||||
[rn/view
|
||||
{:style {:padding-top (safe-area/get-top)}
|
||||
:key :share-community}
|
||||
[quo/page-nav
|
||||
{:icon-name :i/close
|
||||
:on-press navigation-back
|
||||
:on-press events-helper/navigate-back
|
||||
:background :blur
|
||||
:accessibility-label :top-bar}]
|
||||
[quo/page-top
|
||||
|
||||
@@ -4,27 +4,35 @@
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/reg-event-fx :profile/edit-accent-colour-success
|
||||
(fn [_ [customization-color]]
|
||||
(fn [_ [{:keys [customization-color navigate-back? show-toast?]}]]
|
||||
{:fx [[:dispatch [:profile/save-local-accent-color customization-color]]
|
||||
[:dispatch [:navigate-back]]
|
||||
[:dispatch
|
||||
[:toasts/upsert
|
||||
{:type :positive
|
||||
:theme :dark
|
||||
:text (i18n/label :t/accent-colour-updated)}]]]}))
|
||||
(when navigate-back?
|
||||
[:dispatch [:navigate-back]])
|
||||
(when show-toast?
|
||||
[:dispatch
|
||||
[:toasts/upsert
|
||||
{:type :positive
|
||||
:theme :dark
|
||||
:text (i18n/label :t/accent-colour-updated)}]])]}))
|
||||
|
||||
(rf/reg-event-fx :profile/save-local-accent-color
|
||||
(fn [{:keys [db]} [customization-color]]
|
||||
{:db (assoc-in db [:profile/profile :customization-color] customization-color)}))
|
||||
|
||||
(defn edit-accent-colour
|
||||
[{:keys [db]} [customization-color]]
|
||||
[{:keys [db]}
|
||||
[{:keys [color navigate-back? show-toast?]
|
||||
:or {navigate-back? true
|
||||
show-toast? true}}]]
|
||||
(let [key-uid (get-in db [:profile/profile :key-uid])]
|
||||
{:fx [[:json-rpc/call
|
||||
[{:method "wakuext_setCustomizationColor"
|
||||
:params [{:customizationColor customization-color
|
||||
:params [{:customizationColor color
|
||||
:keyUid key-uid}]
|
||||
:on-success [:profile/edit-accent-colour-success customization-color]
|
||||
:on-success [:profile/edit-accent-colour-success
|
||||
{:customization-color color
|
||||
:navigate-back? navigate-back?
|
||||
:show-toast? show-toast?}]
|
||||
:on-error #(log/error "failed to edit accent color." {:error %})}]]]}))
|
||||
|
||||
(rf/reg-event-fx :profile/edit-accent-colour edit-accent-colour)
|
||||
|
||||
@@ -11,7 +11,10 @@
|
||||
[{:method "wakuext_setCustomizationColor"
|
||||
:params [{:customizationColor new-color
|
||||
:keyUid key-uid}]
|
||||
:on-success [:profile/edit-accent-colour-success new-color]
|
||||
:on-success [:profile/edit-accent-colour-success
|
||||
{:customization-color new-color
|
||||
:navigate-back? true
|
||||
:show-toast? true}]
|
||||
:on-error fn?}]]]}]
|
||||
(is (match? expected
|
||||
(sut/edit-accent-colour cofx [new-color])))))
|
||||
(sut/edit-accent-colour cofx [{:color new-color}])))))
|
||||
|
||||
@@ -58,7 +58,8 @@
|
||||
{:type :primary
|
||||
:customization-color @unsaved-custom-color
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:profile/edit-accent-colour @unsaved-custom-color]))}
|
||||
(rf/dispatch [:profile/edit-accent-colour
|
||||
{:color @unsaved-custom-color}]))}
|
||||
(i18n/label :t/save-colour)]]]]))))
|
||||
|
||||
(defn view
|
||||
|
||||
@@ -11,19 +11,22 @@
|
||||
(update db :profile/profile dissoc :images))}))
|
||||
|
||||
(rf/reg-event-fx :profile/edit-profile-picture-success
|
||||
(fn [_ [images]]
|
||||
(let [has-picture? (rf/sub [:profile/has-picture])]
|
||||
(fn [{db :db} [{:keys [show-toast?]} images]]
|
||||
(let [has-picture? (-> db :profile/profile :images count pos?)]
|
||||
{:fx [[:dispatch [:profile/update-local-picture (reverse images)]]
|
||||
[:dispatch
|
||||
[:toasts/upsert
|
||||
{:type :positive
|
||||
:theme :dark
|
||||
:text (i18n/label (if has-picture?
|
||||
:t/profile-picture-updated
|
||||
:t/profile-picture-added))}]]]})))
|
||||
(when show-toast?
|
||||
[:dispatch
|
||||
[:toasts/upsert
|
||||
{:type :positive
|
||||
:theme :dark
|
||||
:text (i18n/label (if has-picture?
|
||||
:t/profile-picture-updated
|
||||
:t/profile-picture-added))}]])]})))
|
||||
|
||||
(defn edit-profile-picture
|
||||
[{:keys [db]} [picture crop-width crop-height]]
|
||||
[{:keys [db]}
|
||||
[{:keys [picture crop-width crop-height show-toast?]
|
||||
:or {show-toast? true}}]]
|
||||
(let [key-uid (get-in db [:profile/profile :key-uid])
|
||||
crop-width (or crop-width profile-picture-picker/crop-size)
|
||||
crop-height (or crop-height profile-picture-picker/crop-size)
|
||||
@@ -31,25 +34,28 @@
|
||||
{:fx [[:json-rpc/call
|
||||
[{:method "multiaccounts_storeIdentityImage"
|
||||
:params [key-uid path 0 0 crop-width crop-height]
|
||||
:on-success [:profile/edit-profile-picture-success]}]]]}))
|
||||
:on-success [:profile/edit-profile-picture-success {:show-toast? show-toast?}]}]]]}))
|
||||
|
||||
(rf/reg-event-fx :profile/edit-picture edit-profile-picture)
|
||||
|
||||
(rf/reg-event-fx :profile/delete-profile-picture-success
|
||||
(fn [_]
|
||||
(fn [_ [{:keys [show-toast?]}]]
|
||||
{:fx [[:dispatch [:profile/update-local-picture nil]]
|
||||
[:dispatch
|
||||
[:toasts/upsert
|
||||
{:type :positive
|
||||
:theme :dark
|
||||
:text (i18n/label :t/profile-picture-removed)}]]]}))
|
||||
(when show-toast?
|
||||
[:dispatch
|
||||
[:toasts/upsert
|
||||
{:type :positive
|
||||
:theme :dark
|
||||
:text (i18n/label :t/profile-picture-removed)}]])]}))
|
||||
|
||||
(defn delete-profile-picture
|
||||
[{:keys [db]}]
|
||||
[{:keys [db]}
|
||||
[{:keys [show-toast?]
|
||||
:or {show-toast? true}}]]
|
||||
(let [key-uid (get-in db [:profile/profile :key-uid])]
|
||||
{:fx [[:json-rpc/call
|
||||
[{:method "multiaccounts_deleteIdentityImage"
|
||||
:params [key-uid]
|
||||
:on-success [:profile/delete-profile-picture-success]}]]]}))
|
||||
:on-success [:profile/delete-profile-picture-success {:show-toast? show-toast?}]}]]]}))
|
||||
|
||||
(rf/reg-event-fx :profile/delete-picture delete-profile-picture)
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
[{:method "multiaccounts_storeIdentityImage"
|
||||
:params [key-uid picture 0 0 profile-picture-picker/crop-size
|
||||
profile-picture-picker/crop-size]
|
||||
:on-success [:profile/edit-profile-picture-success]}]]]}]
|
||||
:on-success [:profile/edit-profile-picture-success {:show-toast? true}]}]]]}]
|
||||
(is (match? expected
|
||||
(sut/edit-profile-picture cofx [picture])))))
|
||||
(sut/edit-profile-picture cofx [{:picture picture}])))))
|
||||
|
||||
(deftest delete-picture-test
|
||||
(let [key-uid "key-uid"
|
||||
@@ -22,6 +22,6 @@
|
||||
expected {:fx [[:json-rpc/call
|
||||
[{:method "multiaccounts_deleteIdentityImage"
|
||||
:params [key-uid]
|
||||
:on-success [:profile/delete-profile-picture-success]}]]]}]
|
||||
:on-success [:profile/delete-profile-picture-success {:show-toast? true}]}]]]}]
|
||||
(is (match? expected
|
||||
(sut/delete-profile-picture cofx)))))
|
||||
(sut/delete-profile-picture cofx [{}])))))
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
has-picture? (rf/sub [:profile/has-picture])
|
||||
on-change-profile-pic (fn [picture]
|
||||
(if picture
|
||||
(rf/dispatch [:profile/edit-picture picture])
|
||||
(rf/dispatch [:profile/edit-picture {:picture picture}])
|
||||
(rf/dispatch [:profile/delete-picture])))]
|
||||
[rn/view
|
||||
{:key :edit-profile
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
(ns status-im.contexts.profile.edit.introduce-yourself.view
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn sheet
|
||||
[{:keys [pending-event]}]
|
||||
(let [on-accept (fn []
|
||||
(rf/dispatch [:open-modal :screen/profile.edit-profile-modal
|
||||
{:pending-event pending-event}]))
|
||||
on-reject #(rf/dispatch pending-event)]
|
||||
[:<>
|
||||
[rn/view {:style {:padding-horizontal 20}}
|
||||
[quo/text
|
||||
{:style {:padding-bottom 4}
|
||||
:size :heading-2
|
||||
:weight :semi-bold}
|
||||
(i18n/label :t/just-introduce-yourself)]
|
||||
[quo/text
|
||||
{:style {:padding-top 4 :padding-bottom 12}
|
||||
:size :paragraph-1
|
||||
:weight :regular}
|
||||
(i18n/label :t/add-display-name-and-picture)]]
|
||||
[quo/bottom-actions
|
||||
{:actions :two-actions
|
||||
:buttons-style {:flex-shrink 1 :flex-basis 0}
|
||||
:button-one-label (i18n/label :t/edit-profile)
|
||||
:button-one-props {:type :primary
|
||||
:on-press on-accept}
|
||||
:button-two-label (i18n/label :t/skip)
|
||||
:button-two-props {:type :grey
|
||||
:on-press on-reject}}]]))
|
||||
@@ -0,0 +1,62 @@
|
||||
(ns status-im.contexts.profile.edit.modal.events
|
||||
(:require [status-im.contexts.profile.edit.introduce-yourself.view :as introduce-yourself]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:profile/edit-profile
|
||||
(fn [_ [{:keys [display-name picture color on-success]}]]
|
||||
{:fx (cond-> []
|
||||
display-name
|
||||
(conj [:dispatch
|
||||
[:profile/edit-name
|
||||
{:display-name display-name
|
||||
:navigate-back? false
|
||||
:show-toast? false}]])
|
||||
color
|
||||
(conj [:dispatch
|
||||
[:profile/edit-accent-colour
|
||||
{:color color
|
||||
:navigate-back? false
|
||||
:show-toast? false}]])
|
||||
picture
|
||||
(conj [:dispatch
|
||||
[:profile/edit-picture
|
||||
{:picture picture
|
||||
:show-toast? false}]])
|
||||
|
||||
(nil? picture)
|
||||
(conj [:dispatch [:profile/delete-picture {:show-toast? false}]])
|
||||
|
||||
:always
|
||||
(conj [:dispatch [:navigate-back]]
|
||||
[:dispatch on-success]))}))
|
||||
|
||||
(defn- profile-update-asked-storage-key
|
||||
[key-uid]
|
||||
(keyword :update-profile-asked key-uid))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:profile/set-profile-update-as-asked
|
||||
(fn [{db :db}]
|
||||
(let [storage-key (-> db :profile/profile :key-uid profile-update-asked-storage-key)]
|
||||
{:fx [[:effects.async-storage/set {storage-key true}]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:profile/ask-profile-update
|
||||
(fn [_ [pending-event]]
|
||||
{:fx [[:dispatch [:profile/set-profile-update-as-asked]]
|
||||
[:dispatch
|
||||
[:show-bottom-sheet
|
||||
{:content (fn []
|
||||
[introduce-yourself/sheet {:pending-event pending-event}])}]]]}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:profile/check-profile-update-prompt
|
||||
(fn [{db :db} [pending-event]]
|
||||
(let [storage-key (-> db :profile/profile :key-uid profile-update-asked-storage-key)]
|
||||
{:fx [[:effects.async-storage/get
|
||||
{:keys [storage-key]
|
||||
:cb (fn [profile-updated-data]
|
||||
(rf/dispatch (if (storage-key profile-updated-data)
|
||||
pending-event
|
||||
[:profile/ask-profile-update pending-event])))}]]})))
|
||||
@@ -0,0 +1,55 @@
|
||||
(ns status-im.contexts.profile.edit.modal.style
|
||||
(:require
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.platform :as platform]))
|
||||
|
||||
(def continue-button
|
||||
{:width "100%"
|
||||
:margin-left :auto
|
||||
:margin-top (if platform/android? :auto 0)
|
||||
:margin-right :auto})
|
||||
|
||||
(def button-container
|
||||
{:width "100%"
|
||||
:padding-left 20
|
||||
:padding-right 20
|
||||
:padding-top 12
|
||||
:align-self :flex-end
|
||||
:height 64})
|
||||
|
||||
(defn view-button-container
|
||||
[keyboard-shown?]
|
||||
(merge button-container
|
||||
(if platform/ios?
|
||||
{:margin-bottom (if keyboard-shown? 0 34)}
|
||||
{:margin-bottom (if keyboard-shown? 12 34)})))
|
||||
|
||||
(def blur-button-container
|
||||
(merge button-container
|
||||
(when platform/android? {:padding-bottom 12})))
|
||||
|
||||
(def page-container
|
||||
{:flex 1})
|
||||
|
||||
(def info-message
|
||||
{:margin-top 8})
|
||||
|
||||
(def title
|
||||
{:color colors/white
|
||||
:margin-top 12
|
||||
:margin-bottom 18})
|
||||
|
||||
(def color-title
|
||||
{:color colors/white-70-blur
|
||||
:margin-top 20
|
||||
:margin-bottom 16})
|
||||
|
||||
(def content-container
|
||||
{:padding-horizontal 20})
|
||||
|
||||
(def input-container
|
||||
{:align-items :flex-start})
|
||||
|
||||
(def profile-input-container
|
||||
{:flex-direction :row
|
||||
:justify-content :center})
|
||||
@@ -0,0 +1,266 @@
|
||||
(ns status-im.contexts.profile.edit.modal.view
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[oops.core :as oops]
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[react-native.hooks :as hooks]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.common.avatar-picture-picker.view :as profile-picture-picker]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[status-im.common.validation.profile :as profile-validator]
|
||||
[status-im.constants :as c]
|
||||
[status-im.contexts.profile.edit.modal.events]
|
||||
[status-im.contexts.profile.edit.modal.style :as style]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.responsiveness :as responsiveness]))
|
||||
|
||||
(def scroll-view-height (reagent/atom 0))
|
||||
(def content-container-height (reagent/atom 0))
|
||||
(def set-scroll-view-height #(reset! scroll-view-height %))
|
||||
|
||||
(defn set-content-container-height
|
||||
[e]
|
||||
(reset! content-container-height (oops/oget e "nativeEvent.layout.height")))
|
||||
|
||||
(defn show-button-background?
|
||||
[keyboard-height keyboard-shown content-scroll-y]
|
||||
(let [button-container-height 64
|
||||
keyboard-view-height (+ keyboard-height button-container-height)]
|
||||
(when keyboard-shown
|
||||
(cond
|
||||
platform/android?
|
||||
(< (- @scroll-view-height button-container-height) @content-container-height)
|
||||
|
||||
platform/ios?
|
||||
(< (- @scroll-view-height keyboard-view-height) (- @content-container-height content-scroll-y))
|
||||
|
||||
:else
|
||||
false))))
|
||||
|
||||
(defn button-container
|
||||
[show-keyboard? keyboard-shown show-background? keyboard-height children]
|
||||
(let [height (reagent/atom 0)]
|
||||
(reset! height (if show-keyboard? (if keyboard-shown keyboard-height 0) 0))
|
||||
[rn/view {:style {:margin-top :auto}}
|
||||
(cond
|
||||
(and (> @height 0) show-background?)
|
||||
[quo/blur
|
||||
(when keyboard-shown
|
||||
{:blur-amount 34
|
||||
:blur-type :transparent
|
||||
:overlay-color :transparent
|
||||
:background-color (if platform/android?
|
||||
colors/neutral-100
|
||||
colors/neutral-80-opa-1-blur)
|
||||
:style style/blur-button-container})
|
||||
children]
|
||||
|
||||
(and (> @height 0) (not show-background?))
|
||||
[rn/view {:style (style/view-button-container true)}
|
||||
children]
|
||||
|
||||
(not show-keyboard?)
|
||||
[rn/view {:style (style/view-button-container false)}
|
||||
children])]))
|
||||
|
||||
(defn- add-keyboard-listener
|
||||
[e callback]
|
||||
(oops/ocall rn/keyboard "addListener" e callback))
|
||||
|
||||
(defn- on-keyboard-show
|
||||
[f]
|
||||
(add-keyboard-listener (if platform/android? "keyboardDidShow" "keyboardWillShow") f))
|
||||
|
||||
(defn- on-keyboard-hide
|
||||
[f]
|
||||
(add-keyboard-listener (if platform/android? "keyboardDidHide" "keyboardWillHide") f))
|
||||
|
||||
(defn floating-button
|
||||
[{:keys [custom-color scroll-y on-submit disabled?]}]
|
||||
(reagent/with-let [show-keyboard? (reagent/atom false)
|
||||
show-listener (on-keyboard-show #(reset! show-keyboard? true))
|
||||
hide-listener (on-keyboard-hide #(reset! show-keyboard? false))]
|
||||
(let [{:keys [keyboard-shown keyboard-height]} (hooks/use-keyboard)
|
||||
show-background? (show-button-background? keyboard-height
|
||||
keyboard-shown
|
||||
scroll-y)]
|
||||
[rn/keyboard-avoiding-view
|
||||
{:style {:position :absolute
|
||||
:top 0
|
||||
:bottom 0
|
||||
:left 0
|
||||
:right 0}
|
||||
:pointer-events :box-none}
|
||||
[button-container @show-keyboard? keyboard-shown show-background? keyboard-height
|
||||
[quo/button
|
||||
{:accessibility-label :submit-create-profile-button
|
||||
:type :primary
|
||||
:customization-color custom-color
|
||||
:on-press on-submit
|
||||
:container-style style/continue-button
|
||||
:disabled? disabled?}
|
||||
(i18n/label :t/continue)]]])
|
||||
(finally
|
||||
(oops/ocall show-listener "remove")
|
||||
(oops/ocall hide-listener "remove"))))
|
||||
|
||||
(defn- content
|
||||
[{:keys [set-display-name set-validation-msg picture-picker]}]
|
||||
(let [open-picture-picker (fn []
|
||||
(rf/dispatch [:dismiss-keyboard])
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content picture-picker
|
||||
:shell? true
|
||||
:theme :dark}]))
|
||||
on-change-text (fn [s]
|
||||
(set-validation-msg s)
|
||||
(set-display-name s))]
|
||||
(fn [{:keys [profile-image custom-color display-name validation-msg valid-name?
|
||||
name-too-short? initial-display-name set-scroll set-scroll-height
|
||||
set-custom-color]}]
|
||||
(let [{window-width :width} (rn/get-window)
|
||||
info-type (cond
|
||||
validation-msg :error
|
||||
name-too-short? :default
|
||||
:else :success)
|
||||
info-message (or validation-msg
|
||||
(i18n/label :t/minimum-characters
|
||||
{:min-chars profile-validator/min-length}))
|
||||
full-name (if (seq display-name)
|
||||
display-name
|
||||
initial-display-name)]
|
||||
[rn/scroll-view
|
||||
{:on-layout set-scroll-height
|
||||
:on-scroll set-scroll
|
||||
:scroll-event-throttle 64
|
||||
:content-container-style {:flex-grow 1}}
|
||||
[rn/view {:on-layout set-content-container-height}
|
||||
[rn/view {:style style/content-container}
|
||||
[quo/text
|
||||
{:style style/title
|
||||
:size :heading-1
|
||||
:weight :semi-bold}
|
||||
(i18n/label :t/edit-profile)]
|
||||
[rn/view {:style style/input-container}
|
||||
[rn/view {:style style/profile-input-container}
|
||||
[quo/profile-input
|
||||
{:customization-color custom-color
|
||||
:placeholder initial-display-name
|
||||
:on-press open-picture-picker
|
||||
:image-picker-props {:profile-picture profile-image
|
||||
:full-name full-name
|
||||
:customization-color custom-color}
|
||||
:title-input-props {:default-value ""
|
||||
:auto-focus true
|
||||
:max-length c/profile-name-max-length
|
||||
:on-change-text on-change-text}}]]
|
||||
[quo/info-message
|
||||
{:status info-type
|
||||
:size :default
|
||||
:icon (if valid-name? :i/positive-state :i/info)
|
||||
:color (when (= :default info-type) colors/white-70-blur)
|
||||
:container-style style/info-message}
|
||||
info-message]
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:weight :medium
|
||||
:style style/color-title}
|
||||
(i18n/label :t/colour)]]]
|
||||
[quo/color-picker
|
||||
{:blur? true
|
||||
:default-selected custom-color
|
||||
:on-change set-custom-color
|
||||
:window-width window-width
|
||||
:container-style {:padding-left (responsiveness/iphone-11-Pro-20-pixel-from-width
|
||||
window-width)}}]]]))))
|
||||
|
||||
(defn- submittable-state?
|
||||
[{:keys [new-color? new-picture? new-name? valid-name?]}]
|
||||
(let [acceptable-name? (or (not new-name?) valid-name?)]
|
||||
(or (and new-color? acceptable-name?)
|
||||
(and new-picture? acceptable-name?)
|
||||
(and new-name? valid-name?))))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [{:keys [pending-event]} (rf/sub [:get-screen-params])
|
||||
{initial-display-name :display-name
|
||||
initial-color :customization-color
|
||||
[initial-image] :images} (rf/sub [:profile/profile])
|
||||
top (safe-area/get-top)
|
||||
scroll-y (reagent/atom 0)
|
||||
display-name (reagent/atom "")
|
||||
validation-msg (reagent/atom (profile-validator/validation-name @display-name))
|
||||
custom-color (reagent/atom (or initial-color c/profile-default-color))
|
||||
profile-image (reagent/atom initial-image)
|
||||
set-display-name #(reset! validation-msg (profile-validator/validation-name %))
|
||||
set-validation-msg #(reset! display-name (string/trim %))
|
||||
set-custom-color #(reset! custom-color %)
|
||||
set-scroll (fn [e]
|
||||
(reset! scroll-y (oops/oget e "nativeEvent.contentOffset.y")))
|
||||
set-scroll-height (fn [e]
|
||||
(reset! scroll-y 0)
|
||||
(-> e
|
||||
(oops/oget "nativeEvent.layout.height")
|
||||
set-scroll-view-height))
|
||||
picture-picker (fn []
|
||||
[profile-picture-picker/view
|
||||
{:on-result #(reset! profile-image %)
|
||||
:has-picture? (some? @profile-image)}])
|
||||
update-profile (fn []
|
||||
(rf/dispatch
|
||||
[:profile/edit-profile
|
||||
(cond-> {:on-success pending-event}
|
||||
(and (seq @display-name)
|
||||
(not= initial-display-name @display-name))
|
||||
(assoc :display-name @display-name)
|
||||
|
||||
(and (not= initial-image @profile-image))
|
||||
(assoc :picture @profile-image)
|
||||
|
||||
(not= initial-color @custom-color)
|
||||
(assoc :color @custom-color))]))
|
||||
on-close (fn []
|
||||
(events-helper/navigate-back)
|
||||
(rf/dispatch pending-event))]
|
||||
(fn []
|
||||
(let [name-too-short? (profile-validator/name-too-short? @display-name)
|
||||
valid-name? (and (not @validation-msg) (not name-too-short?))
|
||||
disabled? (not
|
||||
(submittable-state?
|
||||
{:new-color? (not= initial-color @custom-color)
|
||||
:new-picture? (not= @profile-image initial-image)
|
||||
:new-name? (and (not= initial-display-name @display-name)
|
||||
(seq @display-name))
|
||||
:valid-name? valid-name?}))]
|
||||
[quo/overlay {:type :shell}
|
||||
[rn/view {:style style/page-container}
|
||||
[quo/page-nav
|
||||
{:margin-top top
|
||||
:background :blur
|
||||
:icon-name :i/close
|
||||
:on-press on-close}]
|
||||
[content
|
||||
{:profile-image @profile-image
|
||||
:custom-color @custom-color
|
||||
:display-name @display-name
|
||||
:validation-msg @validation-msg
|
||||
:valid-name? valid-name?
|
||||
:name-too-short? name-too-short?
|
||||
:picture-picker picture-picker
|
||||
:initial-display-name initial-display-name
|
||||
:set-scroll set-scroll
|
||||
:set-scroll-height set-scroll-height
|
||||
:set-custom-color set-custom-color
|
||||
:set-display-name set-display-name
|
||||
:set-validation-msg set-validation-msg}]
|
||||
[floating-button
|
||||
{:custom-color @custom-color
|
||||
:scroll-y @scroll-y
|
||||
:on-submit update-profile
|
||||
:disabled? disabled?}]]]))))
|
||||
@@ -5,21 +5,26 @@
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/reg-event-fx :profile/edit-profile-name-success
|
||||
(fn [_]
|
||||
{:fx [[:dispatch [:navigate-back]]
|
||||
[:dispatch
|
||||
[:toasts/upsert
|
||||
{:type :positive
|
||||
:theme :dark
|
||||
:text (i18n/label :t/name-updated)}]]]}))
|
||||
(fn [{:keys [db]} [display-name navigate-back? show-toast?]]
|
||||
{:db (assoc-in db [:profile/profile :display-name] display-name)
|
||||
:fx [(when navigate-back?
|
||||
[:dispatch [:navigate-back]])
|
||||
(when show-toast?
|
||||
[:dispatch
|
||||
[:toasts/upsert
|
||||
{:type :positive
|
||||
:theme :dark
|
||||
:text (i18n/label :t/name-updated)}]])]}))
|
||||
|
||||
(defn edit-profile-name
|
||||
[{:keys [db]} [name]]
|
||||
{:db (assoc-in db [:profile/profile :display-name] name)
|
||||
:fx [[:json-rpc/call
|
||||
[_
|
||||
[{:keys [display-name navigate-back? show-toast?]
|
||||
:or {navigate-back? true
|
||||
show-toast? true}}]]
|
||||
{:fx [[:json-rpc/call
|
||||
[{:method "wakuext_setDisplayName"
|
||||
:params [name]
|
||||
:on-success [:profile/edit-profile-name-success]}]]]})
|
||||
:params [display-name]
|
||||
:on-success [:profile/edit-profile-name-success display-name navigate-back? show-toast?]}]]]})
|
||||
|
||||
(rf/reg-event-fx :profile/edit-name edit-profile-name)
|
||||
|
||||
|
||||
@@ -6,10 +6,9 @@
|
||||
(deftest edit-name-test
|
||||
(let [new-name "John Doe"
|
||||
cofx {:db {:profile/profile {:display-name "Old name"}}}
|
||||
expected {:db {:profile/profile {:display-name new-name}}
|
||||
:fx [[:json-rpc/call
|
||||
expected {:fx [[:json-rpc/call
|
||||
[{:method "wakuext_setDisplayName"
|
||||
:params [name]
|
||||
:on-success [:profile/edit-profile-name-success]}]]]}]
|
||||
:on-success [:profile/edit-profile-name-success new-name true true]}]]]}]
|
||||
(is (match? expected
|
||||
(sut/edit-profile-name cofx [new-name])))))
|
||||
(sut/edit-profile-name cofx [{:display-name new-name}])))))
|
||||
|
||||
@@ -67,7 +67,8 @@
|
||||
{:type :primary
|
||||
:customization-color customization-color
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:profile/edit-name @full-name]))
|
||||
(rf/dispatch [:profile/edit-name {:display-name @full-name}])
|
||||
(rf/dispatch [:profile/set-profile-update-as-asked]))
|
||||
:disabled? (boolean (or @typing?
|
||||
(string/blank? @full-name)
|
||||
(not (string/blank? @error-msg))))}
|
||||
|
||||
@@ -5,95 +5,42 @@
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[status-im.common.resources :as resources]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.settings.keycard.style :as style]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn registered-keycard
|
||||
[{:keys [profile-name profile-image customization-color]}]
|
||||
[rn/view {:style style/keycard-row}
|
||||
[quo/icon :i/keycard-card
|
||||
{:size 20
|
||||
:color colors/white-70-blur}]
|
||||
[rn/view
|
||||
[quo/text profile-name]
|
||||
[rn/view {:style style/keycard-owner}
|
||||
[quo/user-avatar
|
||||
{:full-name profile-name
|
||||
:profile-picture profile-image
|
||||
:customization-color customization-color
|
||||
:status-indicator false
|
||||
:ring? false
|
||||
:size :xxxs}]
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:style style/keycard-owner-name}
|
||||
profile-name]]]])
|
||||
|
||||
(defn registered-keycards
|
||||
[]
|
||||
(let [keycards (rf/sub [:keycard/registered-keycards])]
|
||||
[:<>
|
||||
[rn/view {:style {:flex 1}}
|
||||
[quo/divider-label
|
||||
{:counter? false
|
||||
:tight? true
|
||||
:blur? true}
|
||||
(i18n/label :t/registered-keycards)]
|
||||
[rn/view {:style style/registered-keycards-container}
|
||||
(for [keycard keycards]
|
||||
^{:key (:keycard-uid keycard)}
|
||||
[registered-keycard keycard])]]
|
||||
[quo/text
|
||||
{:size :heading-2
|
||||
:weight :semi-bold
|
||||
:style {:margin-left 20}}
|
||||
(i18n/label :t/scan-keycard-actions)]
|
||||
[quo/divider-label (i18n/label :t/tips-scan-keycard)]
|
||||
[quo/markdown-list {:description (i18n/label :t/remove-phone-case)}]
|
||||
[quo/markdown-list {:description (i18n/label :t/keep-card-steady)}]
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-label (i18n/label :t/ready-to-scan)
|
||||
:button-one-props {:on-press #(rf/dispatch [:keycard/connect])}}]]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [keycard-profile? (rf/sub [:keycard/keycard-profile?])]
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:key :header
|
||||
:background :blur
|
||||
:icon-name :i/arrow-left
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/keycard)}]
|
||||
(if keycard-profile?
|
||||
[registered-keycards]
|
||||
[rn/view {:style {:padding-horizontal 28 :padding-top 20}}
|
||||
[quo/small-option-card
|
||||
{:variant :main
|
||||
:title (i18n/label :t/get-keycard)
|
||||
:subtitle (i18n/label :t/secure-wallet-card)
|
||||
:button-label (i18n/label :t/buy-keycard)
|
||||
:accessibility-label :get-keycard
|
||||
:image (resources/get-image :keycard-buy)
|
||||
:on-press #(rf/dispatch [:browser.ui/open-url constants/get-keycard-url])}]
|
||||
[rn/view {:style {:margin-top 24}}
|
||||
[quo/text
|
||||
{:style {:margin-bottom 1
|
||||
:color colors/white-opa-70}
|
||||
:size :paragraph-2
|
||||
:weight :medium}
|
||||
(i18n/label :t/own-keycard)]]
|
||||
[quo/small-option-card
|
||||
{:variant :icon
|
||||
:title (i18n/label :t/setup-keycard)
|
||||
:subtitle (i18n/label :t/ready-keycard)
|
||||
:accessibility-label :setup-keycard
|
||||
:image (resources/get-image :use-keycard)
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:open-modal :screen/keycard.check
|
||||
{:on-press
|
||||
#(rf/dispatch
|
||||
[:keycard/migration.check-empty-card])}]))}]])]))
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:key :header
|
||||
:background :blur
|
||||
:icon-name :i/arrow-left
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/keycard)}]
|
||||
[rn/view {:style {:padding-horizontal 28 :padding-top 20}}
|
||||
[quo/small-option-card
|
||||
{:variant :main
|
||||
:title (i18n/label :t/get-keycard)
|
||||
:subtitle (i18n/label :t/secure-wallet-card)
|
||||
:button-label (i18n/label :t/buy-keycard)
|
||||
:accessibility-label :get-keycard
|
||||
:image (resources/get-image :keycard-buy)
|
||||
:on-press #(rf/dispatch [:browser.ui/open-url constants/get-keycard-url])}]
|
||||
[rn/view {:style {:margin-top 24}}
|
||||
[quo/text
|
||||
{:style {:margin-bottom 1
|
||||
:color colors/white-opa-70}
|
||||
:size :paragraph-2
|
||||
:weight :medium}
|
||||
(i18n/label :t/own-keycard)]]
|
||||
[quo/small-option-card
|
||||
{:variant :icon
|
||||
:title (i18n/label :t/manage-keycard)
|
||||
:subtitle (i18n/label :t/setup-keycard-description)
|
||||
:accessibility-label :setup-keycard
|
||||
:image (resources/get-image :use-keycard)
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:open-modal :screen/keycard.check
|
||||
{:on-press
|
||||
#(rf/dispatch [:keycard/check-empty-card])}]))}]]])
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
:z-index (get shared-values
|
||||
(get shell.constants/stacks-z-index-keywords stack-id))})}
|
||||
(case stack-id
|
||||
:communities-stack [:f> communities/view]
|
||||
:chats-stack [:f> chat/view]
|
||||
:communities-stack [communities/view]
|
||||
:chats-stack [chat/view]
|
||||
:wallet-stack [wallet/view]
|
||||
:browser-stack [browser.stack/browser-stack]
|
||||
[:<>])])
|
||||
@@ -38,7 +38,7 @@
|
||||
(defn lazy-screen
|
||||
[stack-id shared-values]
|
||||
(when (load-stack? stack-id)
|
||||
[:f> f-stack-view stack-id shared-values]))
|
||||
[f-stack-view stack-id shared-values]))
|
||||
|
||||
(defn view
|
||||
[shared-values]
|
||||
|
||||
@@ -30,8 +30,7 @@
|
||||
type :no-title}}]
|
||||
(let [{:keys [color emoji watch-only?]} (rf/sub [:wallet/current-viewing-account])
|
||||
networks (rf/sub [:wallet/selected-network-details])
|
||||
sending-collectible? (rf/sub [:wallet/sending-collectible?])
|
||||
keycard? (rf/sub [:wallet/selected-keypair-keycard?])]
|
||||
sending-collectible? (rf/sub [:wallet/sending-collectible?])]
|
||||
[quo/page-nav
|
||||
{:type type
|
||||
:icon-name icon-name
|
||||
@@ -46,11 +45,7 @@
|
||||
(not watch-only?)
|
||||
show-dapps-button?)
|
||||
{:icon-name :i/dapps
|
||||
:on-press #(rf/dispatch
|
||||
(if keycard?
|
||||
[:keycard/feature-unavailable-show
|
||||
{:feature-name :wallet.show-connected-dapps}]
|
||||
[:navigate-to :screen/wallet.connected-dapps]))})
|
||||
:on-press #(rf/dispatch [:navigate-to :screen/wallet.connected-dapps])})
|
||||
(when-not sending-collectible?
|
||||
{:content-type :account-switcher
|
||||
:customization-color color
|
||||
|
||||
@@ -123,3 +123,10 @@
|
||||
(-> (sign-transaction-hashes hashes address password)
|
||||
(promesa/then on-success)
|
||||
(promesa/catch on-error))))
|
||||
|
||||
(rf/reg-fx
|
||||
:effects.wallet/sign-message
|
||||
(fn [{:keys [message address password on-success on-error]}]
|
||||
(-> (wallet-rpc/sign-message message address (security/safe-unmask-data password))
|
||||
(promesa/then on-success)
|
||||
(promesa/catch on-error))))
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
chain-id
|
||||
constants/transaction-pending-type-wallet-connect-transfer
|
||||
(transforms/js-stringify tx-args 0)
|
||||
signature))
|
||||
(utils.hex/normalize-hex signature)))
|
||||
|
||||
(defn sign-message
|
||||
[message address password]
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- crypto-on-ramp-item
|
||||
[{:keys [name description fees logo-url site-url recurrent-site-url urls-need-parameters]
|
||||
[{:keys [name fees logo-url site-url recurrent-site-url urls-need-parameters]
|
||||
:as provider}
|
||||
_
|
||||
_
|
||||
@@ -22,18 +22,16 @@
|
||||
(rn/open-url (if (= tab :recurrent) recurrent-site-url site-url))))
|
||||
[site-url recurrent-site-url tab])]
|
||||
[quo/settings-item
|
||||
{:title name
|
||||
:description :text
|
||||
:description-props {:text description}
|
||||
:tag :context
|
||||
:tag-props {:icon :i/fees
|
||||
:context fees}
|
||||
:action :arrow
|
||||
:action-props {:alignment :flex-start
|
||||
:icon :i/external}
|
||||
:image :icon-avatar
|
||||
:image-props {:icon logo-url}
|
||||
:on-press open-url}]))
|
||||
{:title name
|
||||
:tag :context
|
||||
:tag-props {:icon :i/fees
|
||||
:context fees}
|
||||
:action :arrow
|
||||
:action-props {:alignment :flex-start
|
||||
:icon :i/external}
|
||||
:image :icon-avatar
|
||||
:image-props {:icon logo-url}
|
||||
:on-press open-url}]))
|
||||
|
||||
(def ^:private tabs
|
||||
[{:id :one-time
|
||||
|
||||
@@ -202,18 +202,17 @@
|
||||
:network-image (:source network)}]
|
||||
[data-item
|
||||
{:title (i18n/label :t/max-fees)
|
||||
:subtitle (if (and estimated-time approval-fees-formatted)
|
||||
:subtitle (if approval-fees-formatted
|
||||
approval-fees-formatted
|
||||
(i18n/label :t/unknown))
|
||||
:loading? loading-swap-proposal?
|
||||
:size :small}]
|
||||
[data-item
|
||||
{:title (i18n/label :t/est-time)
|
||||
:subtitle (if estimated-time
|
||||
(i18n/label :t/time-in-mins {:minutes (str estimated-time)})
|
||||
(i18n/label :t/unknown))
|
||||
:loading? loading-swap-proposal?
|
||||
:size :small}]]]))
|
||||
(when estimated-time
|
||||
[data-item
|
||||
{:title (i18n/label :t/est-time)
|
||||
:subtitle (i18n/label :t/time-in-mins {:minutes (str estimated-time)})
|
||||
:loading? loading-swap-proposal?
|
||||
:size :small}])]]))
|
||||
|
||||
(defn- slide-button
|
||||
[]
|
||||
|
||||
@@ -148,15 +148,14 @@
|
||||
max-slippage (rf/sub [:wallet/swap-max-slippage])]
|
||||
[rn/view {:style style/details-container}
|
||||
[:<>
|
||||
[data-item
|
||||
{:title (i18n/label :t/est-time)
|
||||
:subtitle (if estimated-time
|
||||
(i18n/label :t/time-in-mins {:minutes (str estimated-time)})
|
||||
(i18n/label :t/unknown))
|
||||
:loading? loading-swap-proposal?}]
|
||||
(when estimated-time
|
||||
[data-item
|
||||
{:title (i18n/label :t/est-time)
|
||||
:subtitle (i18n/label :t/time-in-mins {:minutes (str estimated-time)})
|
||||
:loading? loading-swap-proposal?}])
|
||||
[data-item
|
||||
{:title (i18n/label :t/max-fees)
|
||||
:subtitle (if (and estimated-time max-fees-formatted) max-fees-formatted (i18n/label :t/unknown))
|
||||
:subtitle (if max-fees-formatted max-fees-formatted (i18n/label :t/unknown))
|
||||
:loading? loading-swap-proposal?}]
|
||||
[data-item
|
||||
{:title (i18n/label :t/max-slippage)
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
(ns status-im.contexts.wallet.wallet-connect.events.effects
|
||||
(:require
|
||||
[native-module.core :as native-module]
|
||||
[promesa.core :as promesa]
|
||||
[react-native.wallet-connect :as wallet-connect]
|
||||
[status-im.config :as config]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.rpc :as wallet-rpc]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.sessions :as sessions]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.signing :as signing]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.transactions :as transactions]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.typed-data :as typed-data]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
[utils.transforms :as transforms]))
|
||||
|
||||
(rf/reg-fx
|
||||
:effects.wallet-connect/init
|
||||
@@ -69,20 +69,21 @@
|
||||
(promesa/catch (partial rf/call-continuation on-fail)))))
|
||||
|
||||
(rf/reg-fx
|
||||
:effects.wallet-connect/sign-message
|
||||
(fn [{:keys [password address data rpc-method on-success on-error]}]
|
||||
(let [password (security/safe-unmask-data password)]
|
||||
(-> (condp =
|
||||
rpc-method
|
||||
:personal-sign
|
||||
(signing/personal-sign password address data)
|
||||
:effects.wallet-connect/hash-message
|
||||
(fn [{:keys [message on-success on-fail]}]
|
||||
(-> (wallet-rpc/hash-message-eip-191 message)
|
||||
(promesa/then (partial rf/call-continuation on-success))
|
||||
(promesa/catch (partial rf/call-continuation on-fail)))))
|
||||
|
||||
:eth-sign
|
||||
(signing/eth-sign password address data)
|
||||
|
||||
(signing/personal-sign password address data))
|
||||
(promesa/then (partial rf/call-continuation on-success))
|
||||
(promesa/catch (partial rf/call-continuation on-error))))))
|
||||
(rf/reg-fx
|
||||
:effects.wallet-connect/hash-typed-data
|
||||
(fn [{:keys [message legacy? on-success on-fail]}]
|
||||
(-> (if legacy?
|
||||
(native-module/hash-typed-data message)
|
||||
(native-module/hash-typed-data-v4 message))
|
||||
(promesa/then (fn [response] (-> response transforms/json->clj :result)))
|
||||
(promesa/then (partial rf/call-continuation on-success))
|
||||
(promesa/catch (partial rf/call-continuation on-fail)))))
|
||||
|
||||
(rf/reg-fx
|
||||
:effects.wallet-connect/prepare-transaction
|
||||
@@ -93,36 +94,12 @@
|
||||
(promesa/then on-success)
|
||||
(promesa/catch on-error))))
|
||||
|
||||
(rf/reg-fx
|
||||
:effects.wallet-connect/sign-transaction
|
||||
(fn [{:keys [password address chain-id tx-hash tx-args on-success on-error]}]
|
||||
(-> (transactions/sign-transaction (security/safe-unmask-data password)
|
||||
address
|
||||
tx-hash
|
||||
tx-args
|
||||
chain-id)
|
||||
(promesa/then (partial rf/call-continuation on-success))
|
||||
(promesa/catch (partial rf/call-continuation on-error)))))
|
||||
|
||||
(rf/reg-fx
|
||||
:effects.wallet-connect/send-transaction
|
||||
(fn [{:keys [password address chain-id tx-hash tx-args on-success on-error]}]
|
||||
(-> (transactions/send-transaction (security/safe-unmask-data password)
|
||||
address
|
||||
tx-hash
|
||||
tx-args
|
||||
chain-id)
|
||||
(promesa/then (partial rf/call-continuation on-success))
|
||||
(promesa/catch (partial rf/call-continuation on-error)))))
|
||||
|
||||
(rf/reg-fx
|
||||
:effects.wallet-connect/sign-typed-data
|
||||
(fn [{:keys [password address data version chain-id on-success on-error]}]
|
||||
(-> (typed-data/sign (security/safe-unmask-data password)
|
||||
address
|
||||
data
|
||||
chain-id
|
||||
version)
|
||||
(fn [{:keys [chain-id signature tx-args on-success on-error]}]
|
||||
(-> (wallet-rpc/send-transaction-with-signature chain-id
|
||||
tx-args
|
||||
signature)
|
||||
(promesa/then (partial rf/call-continuation on-success))
|
||||
(promesa/catch (partial rf/call-continuation on-error)))))
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
(:require [clojure.string :as string]
|
||||
[re-frame.core :as rf]
|
||||
[react-native.wallet-connect :as wallet-connect]
|
||||
[status-im.contexts.wallet.data-store :as wallet-data-store]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
|
||||
data-store]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.networks :as networks]
|
||||
@@ -46,15 +45,8 @@
|
||||
expired? (-> parsed-uri
|
||||
:expiryTimestamp
|
||||
uri/timestamp-expired?)
|
||||
version-supported? (uri/version-supported? version)
|
||||
keycard? (wallet-data-store/selected-keypair-keycard? db)]
|
||||
version-supported? (uri/version-supported? version)]
|
||||
(cond
|
||||
|
||||
keycard?
|
||||
{:fx [[:dispatch
|
||||
[:keycard/feature-unavailable-show
|
||||
{:feature-name :wallet.scan-dapp-connection}]]]}
|
||||
|
||||
(or (not valid-wc-uri?)
|
||||
(not version-supported?)
|
||||
(= network-status :offline)
|
||||
|
||||
@@ -41,12 +41,6 @@
|
||||
[:wallet-connect/process-eth-send-transaction
|
||||
{:on-success (fn [] (rf/dispatch [:wallet-connect/show-request-modal]))}]]
|
||||
|
||||
constants/wallet-connect-eth-sign-method
|
||||
[:dispatch [:wallet-connect/process-eth-sign]]
|
||||
|
||||
constants/wallet-connect-eth-sign-transaction-method
|
||||
[:dispatch [:wallet-connect/process-eth-sign-transaction]]
|
||||
|
||||
constants/wallet-connect-eth-sign-typed-method
|
||||
[:dispatch [:wallet-connect/process-sign-typed]]
|
||||
|
||||
@@ -56,6 +50,13 @@
|
||||
constants/wallet-connect-personal-sign-method
|
||||
[:dispatch [:wallet-connect/process-personal-sign]])]}))))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/store-prepared-hash
|
||||
(fn [{:keys [db]} [prepared-hash]]
|
||||
{:db (assoc-in db
|
||||
[:wallet-connect/current-request :prepared-hash]
|
||||
prepared-hash)}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/process-personal-sign
|
||||
(fn [{:keys [db]}]
|
||||
@@ -65,30 +66,20 @@
|
||||
[:wallet-connect/current-request]
|
||||
assoc
|
||||
:address (string/lower-case address)
|
||||
:raw-data raw-data
|
||||
:display-data (or parsed-data raw-data))
|
||||
:fx [[:dispatch [:wallet-connect/show-request-modal]]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/process-eth-sign
|
||||
(fn [{:keys [db]}]
|
||||
(let [[address raw-data] (data-store/get-db-current-request-params db)
|
||||
parsed-data (native-module/hex-to-utf8 raw-data)]
|
||||
{:db (update-in db
|
||||
[:wallet-connect/current-request]
|
||||
assoc
|
||||
:address (string/lower-case address)
|
||||
:raw-data raw-data
|
||||
:display-data (or parsed-data raw-data))
|
||||
:fx [[:dispatch [:wallet-connect/show-request-modal]]]})))
|
||||
:fx [[:effects.wallet-connect/hash-message
|
||||
{:message raw-data
|
||||
:on-success #(rf/dispatch [:wallet-connect/store-prepared-hash %])
|
||||
:on-fail #(rf/dispatch [:wallet-connect/on-processing-error %])}]
|
||||
[:dispatch [:wallet-connect/show-request-modal]]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/prepare-transaction-success
|
||||
(fn [{:keys [db]} [prepared-tx chain-id]]
|
||||
(let [{:keys [tx-args]} prepared-tx
|
||||
tx (bean/->clj tx-args)
|
||||
address (-> tx :from string/lower-case)
|
||||
display-data (transactions/beautify-transaction tx)]
|
||||
(let [{:keys [tx-args tx-hash]} prepared-tx
|
||||
tx (bean/->clj tx-args)
|
||||
address (-> tx :from string/lower-case)
|
||||
display-data (transactions/beautify-transaction tx)]
|
||||
{:db (update-in db
|
||||
[:wallet-connect/current-request]
|
||||
assoc
|
||||
@@ -96,7 +87,8 @@
|
||||
:raw-data prepared-tx
|
||||
:transaction tx
|
||||
:chain-id chain-id
|
||||
:display-data display-data)})))
|
||||
:display-data display-data)
|
||||
:fx [[:dispatch [:wallet-connect/store-prepared-hash tx-hash]]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/process-eth-send-transaction
|
||||
@@ -116,25 +108,14 @@
|
||||
(rf/call-continuation on-success)))
|
||||
:on-error #(rf/dispatch [:wallet-connect/on-processing-error %])}]]}))))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/process-eth-sign-transaction
|
||||
(fn [{:keys [db]}]
|
||||
(let [event (data-store/get-db-current-request-event db)
|
||||
tx (-> event data-store/get-request-params first)
|
||||
chain-id (-> event
|
||||
(get-in [:params :chainId])
|
||||
networks/eip155->chain-id)]
|
||||
{:fx [[:effects.wallet-connect/prepare-transaction
|
||||
{:tx tx
|
||||
:chain-id chain-id
|
||||
:on-success #(rf/dispatch [:wallet-connect/prepare-transaction-success % chain-id])
|
||||
:on-error #(rf/dispatch [:wallet-connect/on-processing-error %])}]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/process-sign-typed
|
||||
(fn [{:keys [db]}]
|
||||
(try
|
||||
(let [[address raw-data] (data-store/get-db-current-request-params db)
|
||||
method (-> db
|
||||
data-store/get-db-current-request-event
|
||||
data-store/get-request-method)
|
||||
session-chain-id (-> (data-store/get-db-current-request-event db)
|
||||
(get-in [:params :chainId])
|
||||
networks/eip155->chain-id)
|
||||
@@ -154,7 +135,13 @@
|
||||
:address (string/lower-case address)
|
||||
:display-data (typed-data/flatten-typed-data typed-data)
|
||||
:raw-data raw-data)
|
||||
:fx [[:dispatch [:wallet-connect/show-request-modal]]]}))
|
||||
:fx [[:effects.wallet-connect/hash-typed-data
|
||||
{:message raw-data
|
||||
:legacy? (not= constants/wallet-connect-eth-sign-typed-v4-method
|
||||
method)
|
||||
:on-success #(rf/dispatch [:wallet-connect/store-prepared-hash %])
|
||||
:on-fail #(rf/dispatch [:wallet-connect/on-processing-error %])}]
|
||||
[:dispatch [:wallet-connect/show-request-modal]]]}))
|
||||
(catch js/Error err
|
||||
{:fx [[:dispatch
|
||||
[:wallet-connect/on-processing-error
|
||||
|
||||
@@ -2,16 +2,47 @@
|
||||
(:require [re-frame.core :as rf]
|
||||
[react-native.wallet-connect :as wallet-connect]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.keycard.utils :as keycard]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
|
||||
data-store]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.uri :as uri]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.hex :as hex]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.transforms :as transforms]))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/respond-current-session
|
||||
:wallet-connect/authorized-signing
|
||||
(fn [{:keys [db]} [password]]
|
||||
(let [prepared-hash (get-in db [:wallet-connect/current-request :prepared-hash])
|
||||
address (get-in db [:wallet-connect/current-request :address])
|
||||
keycard-sign? (-> (get-in db [:wallet :keypairs])
|
||||
(keycard/keycard-address? address))
|
||||
on-success #(rf/dispatch [:wallet-connect/respond (hex/prefix-hex %)])
|
||||
on-fail #(rf/dispatch [:wallet-connect/on-sign-error %])]
|
||||
(if keycard-sign?
|
||||
{:fx [[:dispatch
|
||||
[:standard-auth/authorize-with-keycard
|
||||
{:on-complete (fn [pin]
|
||||
(rf/dispatch [:keycard/connect-and-sign-hashes
|
||||
{:keycard-pin pin
|
||||
:address address
|
||||
:hashes [prepared-hash]
|
||||
:on-success (fn [signatures]
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(on-success (:signature (first
|
||||
signatures))))
|
||||
:on-failure on-fail}]))}]]]}
|
||||
{:fx [[:effects.wallet/sign-message
|
||||
{:message prepared-hash
|
||||
:address address
|
||||
:password password
|
||||
:on-success on-success
|
||||
:on-error on-fail}]]}))))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/respond
|
||||
(fn [{:keys [db]} [signature]]
|
||||
(let [event (get-in db [:wallet-connect/current-request :event])
|
||||
method (data-store/get-request-method event)
|
||||
screen (data-store/method-to-screen method)
|
||||
@@ -19,83 +50,30 @@
|
||||
(if (uri/timestamp-expired? expiry)
|
||||
{:fx [[:dispatch
|
||||
[:toasts/upsert
|
||||
{:id :new-wallet-account-created
|
||||
:type :negative
|
||||
{:type :negative
|
||||
:text (i18n/label :t/wallet-connect-request-expired)}]]
|
||||
[:dispatch [:dismiss-modal screen]]]}
|
||||
{:fx [(condp = method
|
||||
constants/wallet-connect-personal-sign-method
|
||||
[:dispatch [:wallet-connect/respond-sign-message password :personal-sign]]
|
||||
{:fx [(condp contains? method
|
||||
#{constants/wallet-connect-personal-sign-method
|
||||
constants/wallet-connect-eth-sign-typed-method
|
||||
constants/wallet-connect-eth-sign-typed-v4-method}
|
||||
[:dispatch [:wallet-connect/finish-session-request signature]]
|
||||
|
||||
constants/wallet-connect-eth-sign-method
|
||||
[:dispatch [:wallet-connect/respond-sign-message password :eth-sign]]
|
||||
|
||||
constants/wallet-connect-eth-send-transaction-method
|
||||
[:dispatch [:wallet-connect/respond-send-transaction-data password]]
|
||||
|
||||
constants/wallet-connect-eth-sign-transaction-method
|
||||
[:dispatch [:wallet-connect/respond-sign-transaction-data password]]
|
||||
|
||||
constants/wallet-connect-eth-sign-typed-method
|
||||
[:dispatch [:wallet-connect/respond-sign-typed-data password :v1]]
|
||||
|
||||
constants/wallet-connect-eth-sign-typed-v4-method
|
||||
[:dispatch [:wallet-connect/respond-sign-typed-data password :v4]])]}))))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/respond-sign-message
|
||||
(fn [{:keys [db]} [password rpc-method]]
|
||||
(let [{:keys [address raw-data]} (get db :wallet-connect/current-request)]
|
||||
{:fx [[:effects.wallet-connect/sign-message
|
||||
{:password password
|
||||
:address address
|
||||
:data raw-data
|
||||
:rpc-method rpc-method
|
||||
:on-error [:wallet-connect/on-sign-error]
|
||||
:on-success [:wallet-connect/finish-session-request]}]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/respond-sign-typed-data
|
||||
(fn [{:keys [db]} [password typed-data-version]]
|
||||
(let [{:keys [address raw-data event]} (get db :wallet-connect/current-request)
|
||||
chain-id (get-in event [:params :chainId])]
|
||||
{:fx [[:effects.wallet-connect/sign-typed-data
|
||||
{:password password
|
||||
:address address
|
||||
:data raw-data
|
||||
:chain-id chain-id
|
||||
:version typed-data-version
|
||||
:on-error [:wallet-connect/on-sign-error]
|
||||
:on-success [:wallet-connect/finish-session-request]}]]})))
|
||||
#{constants/wallet-connect-eth-send-transaction-method}
|
||||
[:dispatch [:wallet-connect/respond-send-transaction-data signature]])]}))))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/respond-send-transaction-data
|
||||
(fn [{:keys [db]} [password]]
|
||||
(let [{:keys [chain-id raw-data address]} (get db :wallet-connect/current-request)
|
||||
{:keys [tx-hash tx-args]} raw-data]
|
||||
(fn [{:keys [db]} [signature]]
|
||||
(let [{:keys [chain-id raw-data]} (get db :wallet-connect/current-request)
|
||||
{:keys [tx-args]} raw-data]
|
||||
{:fx [[:effects.wallet-connect/send-transaction
|
||||
{:password password
|
||||
:address address
|
||||
{:signature signature
|
||||
:chain-id chain-id
|
||||
:tx-hash tx-hash
|
||||
:tx-args tx-args
|
||||
:on-error [:wallet-connect/on-sign-error]
|
||||
:on-success [:wallet-connect/finish-session-request]}]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/respond-sign-transaction-data
|
||||
(fn [{:keys [db]} [password]]
|
||||
(let [{:keys [chain-id raw-data address]} (get db :wallet-connect/current-request)
|
||||
{:keys [tx-hash tx-args]} raw-data]
|
||||
{:fx [[:effects.wallet-connect/sign-transaction
|
||||
{:password password
|
||||
:address address
|
||||
:chain-id chain-id
|
||||
:tx-hash tx-hash
|
||||
:tx-params tx-args
|
||||
:on-error [:wallet-connect/on-sign-error]
|
||||
:on-success [:wallet-connect/finish-session-request]}]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/on-sign-error
|
||||
(fn [{:keys [db]} [error]]
|
||||
|
||||
@@ -12,13 +12,14 @@
|
||||
(defn- on-auth-success
|
||||
[password]
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(rf/dispatch [:wallet-connect/respond-current-session password]))
|
||||
(rf/dispatch [:wallet-connect/authorized-signing password]))
|
||||
|
||||
(defn view
|
||||
[{:keys [warning-label slide-button-text error-state]} & children]
|
||||
(let [{:keys [customization-color]} (rf/sub [:wallet-connect/current-request-account-details])
|
||||
offline? (rf/sub [:network/offline?])
|
||||
theme (quo.theme/use-theme)]
|
||||
theme (quo.theme/use-theme)
|
||||
sign-on-keycard? (rf/sub [:wallet-connect/sign-on-keycard?])]
|
||||
[:<>
|
||||
(when (or offline? error-state)
|
||||
[quo/alert-banner
|
||||
@@ -48,6 +49,8 @@
|
||||
:disabled? (or offline? error-state)
|
||||
:customization-color customization-color
|
||||
:on-auth-success on-auth-success
|
||||
:on-complete (when sign-on-keycard?
|
||||
#(on-auth-success ""))
|
||||
:auth-button-label (i18n/label :t/confirm)}]]
|
||||
[rn/view {:style style/warning-container}
|
||||
[quo/text
|
||||
|
||||
@@ -30,10 +30,8 @@
|
||||
(def method-to-screen
|
||||
{constants/wallet-connect-personal-sign-method :screen/wallet-connect.sign-message
|
||||
constants/wallet-connect-eth-sign-typed-method :screen/wallet-connect.sign-message
|
||||
constants/wallet-connect-eth-sign-method :screen/wallet-connect.sign-message
|
||||
constants/wallet-connect-eth-sign-typed-v4-method :screen/wallet-connect.sign-message
|
||||
constants/wallet-connect-eth-send-transaction-method :screen/wallet-connect.send-transaction
|
||||
constants/wallet-connect-eth-sign-transaction-method :screen/wallet-connect.sign-transaction})
|
||||
constants/wallet-connect-eth-send-transaction-method :screen/wallet-connect.send-transaction})
|
||||
|
||||
(defn extract-native-call-signature
|
||||
[data]
|
||||
@@ -59,11 +57,11 @@
|
||||
|
||||
(defn get-current-request-dapp
|
||||
[request sessions]
|
||||
(let [dapp-url (get-in request [:event :verifyContext :verified :origin])]
|
||||
(let [request-topic (get-in request [:event :topic])]
|
||||
(->> sessions
|
||||
(filter (fn [session]
|
||||
(= (utils.string/remove-trailing-slash dapp-url)
|
||||
(utils.string/remove-trailing-slash (get session :url)))))
|
||||
(= (:topic session)
|
||||
request-topic)))
|
||||
first)))
|
||||
|
||||
(defn get-dapp-redirect-url
|
||||
|
||||
@@ -8,15 +8,15 @@
|
||||
|
||||
(deftest get-current-request-dapp-test
|
||||
(testing "returns the correct dapp based on the request's origin"
|
||||
(let [request {:event {:verifyContext {:verified {:origin "https://dapp.com"}}}}
|
||||
sessions [{:url "https://dapp.com"}
|
||||
{:url "https://anotherdapp.com"}]]
|
||||
(is (= {:url "https://dapp.com"}
|
||||
(let [request {:event {:topic "123"}}
|
||||
sessions [{:topic "123"}
|
||||
{:topic "456"}]]
|
||||
(is (= {:topic "123"}
|
||||
(sut/get-current-request-dapp request sessions)))))
|
||||
|
||||
(testing "returns nil if no matching dapp is found"
|
||||
(let [request {:event {:verifyContext {:verified {:origin "https://dapp.com"}}}}
|
||||
sessions [{:url "https://anotherdapp.com"}]]
|
||||
(let [request {:event {:topic "123"}}
|
||||
sessions [{:topic "456"}]]
|
||||
(is (nil? (sut/get-current-request-dapp request sessions))))))
|
||||
|
||||
(deftest get-dapp-redirect-url-test
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
(ns status-im.contexts.wallet.wallet-connect.utils.signing
|
||||
(:require
|
||||
[native-module.core :as native-module]
|
||||
[promesa.core :as promesa]
|
||||
[status-im.contexts.wallet.rpc :as wallet-rpc]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
|
||||
data-store]
|
||||
[utils.hex :as hex]
|
||||
[utils.transforms :as transforms]))
|
||||
|
||||
(defn eth-sign
|
||||
[password address data]
|
||||
(-> {:data data
|
||||
:account address
|
||||
:password password}
|
||||
transforms/clj->json
|
||||
native-module/sign-message
|
||||
(promesa/then data-store/extract-native-call-signature)))
|
||||
|
||||
(defn personal-sign
|
||||
[password address data]
|
||||
(-> (wallet-rpc/hash-message-eip-191 data)
|
||||
(promesa/then #(wallet-rpc/sign-message % address password))
|
||||
(promesa/then hex/prefix-hex)))
|
||||
@@ -14,8 +14,7 @@
|
||||
(defn transaction-request?
|
||||
[event]
|
||||
(->> (data-store/get-request-method event)
|
||||
(contains? #{constants/wallet-connect-eth-send-transaction-method
|
||||
constants/wallet-connect-eth-sign-transaction-method})))
|
||||
(contains? constants/wallet-connect-transaction-methods)))
|
||||
|
||||
;; NOTE: Currently we don't allow the user to configure the tx priority as we don't
|
||||
;; show the estimated time, but when we implement it, we should allow to change it
|
||||
@@ -136,22 +135,6 @@
|
||||
:suggested-fees suggested-fees
|
||||
:estimated-time estimated-time}))
|
||||
|
||||
(defn sign-transaction
|
||||
[password address tx-hash tx-args chain-id]
|
||||
(promesa/let
|
||||
[signature (wallet-rpc/sign-message tx-hash address password)
|
||||
raw-tx (wallet-rpc/build-raw-transaction chain-id tx-args signature)]
|
||||
raw-tx))
|
||||
|
||||
(defn send-transaction
|
||||
[password address tx-hash tx-args chain-id]
|
||||
(promesa/let
|
||||
[signature (wallet-rpc/sign-message tx-hash address password)
|
||||
tx (wallet-rpc/send-transaction-with-signature chain-id
|
||||
tx-args
|
||||
signature)]
|
||||
tx))
|
||||
|
||||
(defn transactions->display-array
|
||||
[data]
|
||||
(remove (fn [[k v]]
|
||||
|
||||
@@ -31,12 +31,14 @@
|
||||
[status-im.contexts.communities.discover.view :as communities.discover]
|
||||
[status-im.contexts.communities.overview.view :as communities.overview]
|
||||
[status-im.contexts.keycard.authorise.view :as keycard.authorise]
|
||||
[status-im.contexts.keycard.backup.view :as keycard.backup]
|
||||
[status-im.contexts.keycard.check.view :as keycard.check]
|
||||
[status-im.contexts.keycard.create.view :as keycard.create]
|
||||
[status-im.contexts.keycard.different-card.view :as keycard.different-card]
|
||||
[status-im.contexts.keycard.empty.view :as keycard.empty]
|
||||
[status-im.contexts.keycard.error.view :as keycard.error]
|
||||
[status-im.contexts.keycard.factory-reset.view :as keycard.factory-reset]
|
||||
[status-im.contexts.keycard.manage.profile-keys.view :as keycard.manage.profile-keys]
|
||||
[status-im.contexts.keycard.migrate.fail.view :as keycard.migrate.fail]
|
||||
[status-im.contexts.keycard.migrate.profile-keys.view :as keycard.migrate.profile-keys]
|
||||
[status-im.contexts.keycard.migrate.re-encrypting.view :as keycard.re-encrypting]
|
||||
@@ -64,6 +66,7 @@
|
||||
[status-im.contexts.profile.contact.view :as contact-profile]
|
||||
[status-im.contexts.profile.edit.accent-colour.view :as edit-accent-colour]
|
||||
[status-im.contexts.profile.edit.bio.view :as edit-bio]
|
||||
[status-im.contexts.profile.edit.modal.view :as edit-profile-modal]
|
||||
[status-im.contexts.profile.edit.name.view :as edit-name]
|
||||
[status-im.contexts.profile.edit.view :as edit-profile]
|
||||
[status-im.contexts.profile.profiles.view :as profiles]
|
||||
@@ -1003,13 +1006,20 @@
|
||||
:insets {:top? true :bottom? true}}
|
||||
:component keycard.pin.enter/view}
|
||||
|
||||
{:name :screen/keycard.profile-keys
|
||||
{:name :screen/keycard.migrate.profile-keys
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:modalPresentationStyle :fullScreen
|
||||
:insets {:top? true :bottom? true}}
|
||||
:component keycard.migrate.profile-keys/view}
|
||||
|
||||
{:name :screen/keycard.manage.profile-keys
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:modalPresentationStyle :fullScreen
|
||||
:insets {:top? true :bottom? true}}
|
||||
:component keycard.manage.profile-keys/view}
|
||||
|
||||
{:name :screen/keycard.create-profile
|
||||
:metrics {:track? true}
|
||||
:options {:insets {:top? true :bottom? true}
|
||||
@@ -1034,7 +1044,36 @@
|
||||
:options {:theme :dark
|
||||
:modalPresentationStyle :fullScreen
|
||||
:insets {:top? true :bottom? true}}
|
||||
:component keycard.factory-reset/failed-view}])
|
||||
:component keycard.factory-reset/failed-view}
|
||||
|
||||
{:name :screen/keycard.backup.scan-empty
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:modalPresentationStyle :fullScreen
|
||||
:insets {:top? true :bottom? true}}
|
||||
:component keycard.backup/scan-empty}
|
||||
|
||||
{:name :screen/keycard.backup.not-empty
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:modalPresentationStyle :fullScreen
|
||||
:insets {:top? true :bottom? true}}
|
||||
:component keycard.backup/not-empty-view}
|
||||
|
||||
{:name :screen/keycard.backup.ready-to-add
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:modalPresentationStyle :fullScreen
|
||||
:insets {:top? true :bottom? true}}
|
||||
:component keycard.backup/ready-to-add}
|
||||
|
||||
{:name :screen/keycard.backup.success
|
||||
:metrics {:track? true}
|
||||
:options {:theme :dark
|
||||
:modalPresentationStyle :fullScreen
|
||||
:insets {:top? true :bottom? true}}
|
||||
:component keycard.backup/success-view}])
|
||||
|
||||
|
||||
(defn screens
|
||||
[]
|
||||
@@ -1127,7 +1166,12 @@
|
||||
:options {:theme :dark
|
||||
:layout options/onboarding-layout}
|
||||
:on-focus [:onboarding/overlay-dismiss]
|
||||
:component profiles/view}]
|
||||
:component profiles/view}
|
||||
|
||||
{:name :screen/profile.edit-profile-modal
|
||||
:metrics {:track? true}
|
||||
:options options/transparent-screen-options
|
||||
:component edit-profile-modal/view}]
|
||||
|
||||
[{:name :shell
|
||||
:metrics {:track? true}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
(ns status-im.subs.wallet.dapps.requests
|
||||
(:require [re-frame.core :as rf]
|
||||
[status-im.contexts.keycard.utils :as keycard]
|
||||
[status-im.contexts.wallet.common.utils :as wallet-utils]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
|
||||
data-store]
|
||||
@@ -59,3 +60,10 @@
|
||||
:wallet-connect/typed-data-request?
|
||||
:<- [:wallet-connect/current-request-method]
|
||||
typed-data/typed-data-request?)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet-connect/sign-on-keycard?
|
||||
:<- [:wallet/keypairs]
|
||||
:<- [:wallet-connect/current-request-address]
|
||||
(fn [[keypairs address]]
|
||||
(keycard/keycard-address? keypairs address)))
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
(fn []
|
||||
(let [new-name "John Doe"]
|
||||
(promesa/do
|
||||
(rf/dispatch [:profile/edit-name new-name])
|
||||
(rf/dispatch [:profile/edit-name {:display-name new-name}])
|
||||
(h/wait-for [:navigate-back :toasts/upsert])
|
||||
(let [profile (rf/sub [:profile/profile])
|
||||
display-name (profile.utils/displayed-name profile)]
|
||||
@@ -26,7 +26,10 @@
|
||||
(let [mock-image "resources/images/mock2/monkey.png"
|
||||
absolute-path (.resolve test-utils/path mock-image)]
|
||||
(promesa/do
|
||||
(rf/dispatch [:profile/edit-picture absolute-path 80 80])
|
||||
(rf/dispatch [:profile/edit-picture
|
||||
{:picture absolute-path
|
||||
:crop-width 80
|
||||
:crop-height 80}])
|
||||
(h/wait-for [:profile/update-local-picture :toasts/upsert])
|
||||
(let [profile (rf/sub [:profile/profile])]
|
||||
(is (not (nil? (:images profile))))))))))
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
|
||||
"owner": "status-im",
|
||||
"repo": "status-go",
|
||||
"version": "v9.1.0",
|
||||
"commit-sha1": "4ec885a91f2857a30d1838213000f0a5a91fd52a",
|
||||
"src-sha256": "1fkvhazv7v2vyqpffx3r4p3aii5ai464nx2pdfgn6b6gmb24bxdq"
|
||||
"version": "fix/applying-removed-contact",
|
||||
"commit-sha1": "0690be2819b227e42d588756b17b26faae8e8b4c",
|
||||
"src-sha256": "0ip1zsnn94pfy92hj3v3kcbfc1z3gg32qnhjd78xzgsl6bvc0k51"
|
||||
}
|
||||
|
||||
@@ -40,9 +40,10 @@ class TestActivityCenterContactRequestMultipleDevicePR(MultipleSharedDeviceTestC
|
||||
if text_name != self.username_1 and text_name != "%s...%s" % (
|
||||
self.public_key_1[:3], self.public_key_1[-6:]):
|
||||
self.errors.append(
|
||||
self.home_2,
|
||||
"Neither username nor public key is shown on 'Add contact' page after entering valid public key")
|
||||
else:
|
||||
self.errors.append("User is not found on 'Add contact' page after entering valid public key")
|
||||
self.errors.append(self.home_2, "User is not found on 'Add contact' page after entering valid public key")
|
||||
chat = self.home_2.get_chat_view()
|
||||
|
||||
chat.view_profile_new_contact_button.click_until_presence_of_element(chat.profile_send_contact_request_button)
|
||||
@@ -55,7 +56,8 @@ class TestActivityCenterContactRequestMultipleDevicePR(MultipleSharedDeviceTestC
|
||||
self.device_1.just_fyi("Device 1: check there is no PN when receiving new message to activity centre")
|
||||
self.device_1.open_notification_bar()
|
||||
if self.home_1.element_by_text_part("Please add me to your contacts").is_element_displayed():
|
||||
self.errors.append("Push notification with text was received for new message in activity centre")
|
||||
self.errors.append(self.home_1,
|
||||
"Push notification with text was received for new message in activity centre")
|
||||
self.device_1.click_system_back_button()
|
||||
self.device_1.driver.activate_app(app_package)
|
||||
self.device_1.wait_for_application_to_be_running(app_package)
|
||||
@@ -65,9 +67,9 @@ class TestActivityCenterContactRequestMultipleDevicePR(MultipleSharedDeviceTestC
|
||||
for indicator in (self.home_1.notifications_unread_badge, self.home_1.contact_new_badge):
|
||||
if not indicator.is_element_displayed():
|
||||
self.errors.append(
|
||||
"Unread indicator on contacts tab or on activity center is not shown for incoming CR!")
|
||||
self.home_1, "Unread indicator on contacts tab or on activity center is not shown for incoming CR!")
|
||||
if self.home_1.pending_contact_request_text.text != '1':
|
||||
self.errors.append("The amount of contact requests is not shown for incoming CR!")
|
||||
self.errors.append(self.home_1, "The amount of contact requests is not shown for incoming CR!")
|
||||
|
||||
self.device_1.just_fyi('Device1 declines pending contact request')
|
||||
self.home_1.handle_contact_request(username=self.username_2, action='decline')
|
||||
@@ -75,6 +77,7 @@ class TestActivityCenterContactRequestMultipleDevicePR(MultipleSharedDeviceTestC
|
||||
self.home_1.pending_contact_request_text):
|
||||
if indicator.is_element_displayed():
|
||||
self.errors.append(
|
||||
self.home_1,
|
||||
"Unread indicator on contacts tab or on activity center is shown after declining contact request!")
|
||||
|
||||
self.device_1.just_fyi("Check that it is still pending contact after declining on sender device")
|
||||
@@ -85,7 +88,7 @@ class TestActivityCenterContactRequestMultipleDevicePR(MultipleSharedDeviceTestC
|
||||
if element.title.text != 'Contact request' or element.context_tag_text != self.username_1 \
|
||||
or not element.pending_status_tag.is_element_displayed():
|
||||
self.errors.append(
|
||||
"Pending contact request is not shown on unread notification element on Activity center!")
|
||||
self.home_2, "Pending contact request is not shown on unread notification element on Activity center!")
|
||||
self.home_2.close_activity_centre.click()
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
@@ -123,7 +126,8 @@ class TestActivityCenterContactRequestMultipleDevicePR(MultipleSharedDeviceTestC
|
||||
self.home_1.more_options_activity_button.click()
|
||||
self.home_1.mark_all_read_activity_button.click()
|
||||
if cr_element.is_element_displayed():
|
||||
self.errors.append("Contact request is still shown in activity centre after marking all messages as read!")
|
||||
self.errors.append(
|
||||
self.home_1, "Contact request is still shown in activity centre after marking all messages as read!")
|
||||
|
||||
self.home_1.just_fyi("Check that can accept contact request from read notifications")
|
||||
self.home_1.activity_unread_filter_button.click()
|
||||
@@ -132,14 +136,16 @@ class TestActivityCenterContactRequestMultipleDevicePR(MultipleSharedDeviceTestC
|
||||
self.home_1.close_activity_centre.click()
|
||||
self.home_1.contacts_tab.click()
|
||||
if not self.home_1.contact_details_row(username=new_username).is_element_displayed(20):
|
||||
self.errors.append("Contact was not added to contact list after accepting contact request (as receiver)")
|
||||
self.errors.append(self.home_1,
|
||||
"Contact was not added to contact list after accepting contact request (as receiver)")
|
||||
|
||||
self.device_2.just_fyi('Device1 check that contact appeared in contact list mutually')
|
||||
self.home_2.navigate_back_to_home_view()
|
||||
self.home_2.chats_tab.click()
|
||||
self.home_2.contacts_tab.click()
|
||||
if not self.home_2.contact_details_row(username=self.username_1).is_element_displayed(20):
|
||||
self.errors.append("Contact was not added to contact list after accepting contact request (as sender)")
|
||||
self.errors.append(self.home_2,
|
||||
"Contact was not added to contact list after accepting contact request (as sender)")
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@@ -172,9 +178,10 @@ class TestActivityCenterContactRequestMultipleDevicePR(MultipleSharedDeviceTestC
|
||||
text_name = self.home_1.user_name_text.text
|
||||
if text_name != self.username_2 and text_name != "%s...%s" % (public_key_2[:3], public_key_2[-6:]):
|
||||
self.errors.append(
|
||||
self.home_1,
|
||||
"Neither username nor public key is shown on 'Add contact' page after entering valid profile link")
|
||||
else:
|
||||
self.errors.append("User is not found on 'Add contact' page after entering valid public key")
|
||||
self.errors.append(self.home_1, "User is not found on 'Add contact' page after entering valid public key")
|
||||
chat_1 = self.home_1.get_chat_view()
|
||||
chat_1.view_profile_new_contact_button.click_until_presence_of_element(
|
||||
chat_1.profile_send_contact_request_button)
|
||||
@@ -197,9 +204,10 @@ class TestActivityCenterContactRequestMultipleDevicePR(MultipleSharedDeviceTestC
|
||||
text_name = self.home_1.user_name_text.text
|
||||
if text_name != self.username_2 and text_name != "%s...%s" % (public_key_2[:3], public_key_2[-6:]):
|
||||
self.errors.append(
|
||||
self.home_1,
|
||||
"Neither username nor public key is shown on 'Add contact' page after entering valid public key")
|
||||
else:
|
||||
self.errors.append("User is not found on 'Add contact' page after entering valid public key")
|
||||
self.errors.append(self.home_1, "User is not found on 'Add contact' page after entering valid public key")
|
||||
|
||||
self.home_2.just_fyi("Device 2 gets sync code")
|
||||
self.home_2.navigate_back_to_home_view()
|
||||
@@ -217,7 +225,7 @@ class TestActivityCenterContactRequestMultipleDevicePR(MultipleSharedDeviceTestC
|
||||
try:
|
||||
self.home_1.element_by_translation_id("invalid-ens-or-key").wait_for_visibility_of_element()
|
||||
except TimeoutException:
|
||||
self.errors.append("Error message is not shown for value \"%s\"" % value)
|
||||
self.errors.append(self.home_1, "Error message is not shown for value \"%s\"" % value)
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@@ -266,15 +274,16 @@ class TestActivityMultipleDevicePR(MultipleSharedDeviceTestCase):
|
||||
self.community_1.click_on_floating_jump_to()
|
||||
for card in (self.community_name, self.username_2):
|
||||
if not self.community_1.element_by_text_part(card).is_element_displayed(20):
|
||||
self.errors.append("Card %s is not shown on Jump to screen!" % card)
|
||||
self.errors.append(self.community_1, "Card %s is not shown on Jump to screen!" % card)
|
||||
self.community_1.element_by_translation_id("community-channel").click()
|
||||
if not self.channel_1.chat_element_by_text(self.text_message).is_element_displayed(20):
|
||||
self.errors.append("User was not redirected to community channel after tapping on community channel card!")
|
||||
self.errors.append(self.channel_1,
|
||||
"User was not redirected to community channel after tapping on community channel card!")
|
||||
self.channel_1.click_system_back_button()
|
||||
self.community_1.click_on_floating_jump_to()
|
||||
self.community_1.element_by_text_part(self.username_2).click()
|
||||
if not self.chat_1.chat_element_by_text(self.one_to_one_message).is_element_displayed(20):
|
||||
self.errors.append("User was not redirected to 1-1 chat after tapping card!")
|
||||
self.errors.append(self.chat_1, "User was not redirected to 1-1 chat after tapping card!")
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@@ -298,29 +307,29 @@ class TestActivityMultipleDevicePR(MultipleSharedDeviceTestCase):
|
||||
community_element_1 = self.home_1.get_chat(self.community_name, community=True)
|
||||
for unread_counter in community_element_1.new_messages_counter, self.home_1.communities_tab.counter:
|
||||
if not unread_counter.is_element_displayed(60):
|
||||
self.errors.append('New message counter badge is not shown!')
|
||||
self.errors.append(self.home_1, 'New message counter badge is not shown!')
|
||||
if int(unread_counter.text) != 1:
|
||||
self.errors.append('New message counter badge is not 1, it is %s!' % unread_counter.text)
|
||||
self.errors.append(self.home_1, 'New message counter badge is not 1, it is %s!' % unread_counter.text)
|
||||
|
||||
self.home_1.just_fyi("Checking reply attributes in activity center")
|
||||
self.home_1.open_activity_center_button.click()
|
||||
reply_element = self.home_1.get_element_from_activity_center_view(reply_to_message_from_sender)
|
||||
if reply_element.title.text != 'Reply':
|
||||
self.errors.append("Expected title is not shown, '%s' is instead!" % reply_element.title)
|
||||
self.errors.append(self.home_1, "Expected title is not shown, '%s' is instead!" % reply_element.title)
|
||||
if not reply_element.unread_indicator.is_element_displayed():
|
||||
self.errors.append("No unread dot is shown on activity center element!")
|
||||
self.errors.append(self.home_1, "No unread dot is shown on activity center element!")
|
||||
|
||||
self.home_2.chats_tab.is_element_displayed() # just saving device 2 session from expiration
|
||||
|
||||
self.home_1.just_fyi("Swiping to 'Replies' on activity center and check unread there")
|
||||
self.home_1.mention_activity_tab_button.click()
|
||||
if reply_element.is_element_displayed(2):
|
||||
self.errors.append("Filter on mentions is not working in Activity centre!")
|
||||
self.errors.append(self.home_1, "Filter on mentions is not working in Activity centre!")
|
||||
self.home_1.reply_activity_tab_button.click()
|
||||
if not self.home_1.reply_activity_tab_button.counter.is_element_displayed(2):
|
||||
self.errors.append("No unread dot is shown on activity center tab element!")
|
||||
self.errors.append(self.home_1, "No unread dot is shown on activity center tab element!")
|
||||
if not reply_element.is_element_displayed():
|
||||
self.errors.append("Filter on replies tab is not working in Activity centre!")
|
||||
self.errors.append(self.home_1, "Filter on replies tab is not working in Activity centre!")
|
||||
|
||||
self.home_2.chats_tab.is_element_displayed() # just saving device 2 session from expiration
|
||||
|
||||
@@ -328,10 +337,10 @@ class TestActivityMultipleDevicePR(MultipleSharedDeviceTestCase):
|
||||
reply_element.title.swipe_right_on_element(width_percentage=6)
|
||||
self.home_1.activity_notification_swipe_button.click()
|
||||
if reply_element.is_element_displayed(2):
|
||||
self.errors.append("Message is not marked as read!")
|
||||
self.errors.append(self.home_1, "Message is not marked as read!")
|
||||
self.home_1.activity_unread_filter_button.click()
|
||||
if not reply_element.is_element_displayed(2):
|
||||
self.errors.append("Read filter is not displayed read message!")
|
||||
self.errors.append(self.home_1, "Read filter is not displayed read message!")
|
||||
|
||||
self.home_2.chats_tab.is_element_displayed() # just saving device 2 session from expiration
|
||||
|
||||
@@ -339,16 +348,18 @@ class TestActivityMultipleDevicePR(MultipleSharedDeviceTestCase):
|
||||
reply_element.title.swipe_right_on_element(width_percentage=6)
|
||||
self.home_1.activity_notification_swipe_button.click()
|
||||
if not reply_element.unread_indicator.is_element_displayed():
|
||||
self.errors.append("No unread dot is shown on activity center element after marking it as unread!")
|
||||
self.errors.append(self.home_1,
|
||||
"No unread dot is shown on activity center element after marking it as unread!")
|
||||
|
||||
self.home_1.just_fyi("Tap on it and check it marked as read")
|
||||
reply_element.click()
|
||||
if not self.channel_1.chat_element_by_text(reply_to_message_from_sender).is_element_displayed():
|
||||
self.errors.append("Was not redirected to chat after tapping on reply!")
|
||||
self.errors.append(self.home_1, "Was not redirected to chat after tapping on reply!")
|
||||
self.home_1.navigate_back_to_home_view()
|
||||
self.home_1.communities_tab.click()
|
||||
if self.home_1.notifications_unread_badge.is_element_displayed():
|
||||
self.errors.append("Notification was not marked as read after opening it in community channel!")
|
||||
self.errors.append(self.home_1,
|
||||
"Notification was not marked as read after opening it in community channel!")
|
||||
|
||||
self.home_2.chats_tab.is_element_displayed() # just saving device 2 session from expiration
|
||||
|
||||
@@ -357,7 +368,7 @@ class TestActivityMultipleDevicePR(MultipleSharedDeviceTestCase):
|
||||
reply_element.swipe_left_on_element()
|
||||
self.home_1.activity_notification_swipe_button.click()
|
||||
if reply_element.is_element_displayed():
|
||||
self.errors.append("Reply is still shown after removing from activity centre!")
|
||||
self.errors.append(self.home_1, "Reply is still shown after removing from activity centre!")
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@@ -414,25 +425,26 @@ class TestActivityMultipleDevicePRTwo(MultipleSharedDeviceTestCase):
|
||||
community_element_1 = self.home_1.get_chat(self.community_name, community=True)
|
||||
for unread_counter in community_element_1.new_messages_counter, self.home_1.communities_tab.counter:
|
||||
if not unread_counter.is_element_displayed(60):
|
||||
self.errors.append('New message counter badge is not shown while mentioned!')
|
||||
self.errors.append(self.home_1, 'New message counter badge is not shown while mentioned!')
|
||||
if int(unread_counter.text) != 1:
|
||||
self.errors.append('New message counter badge is not 1, it is %s!' % unread_counter.text)
|
||||
self.errors.append(self.home_1, 'New message counter badge is not 1, it is %s!' % unread_counter.text)
|
||||
|
||||
self.home_1.just_fyi("Checking mention attributes in activity center")
|
||||
self.home_1.open_activity_center_button.click()
|
||||
mention_element = self.home_1.get_element_from_activity_center_view('@%s' % self.username_1)
|
||||
if mention_element.title.text != 'Mention':
|
||||
self.errors.append("Expected title is not shown, '%s' is instead!" % mention_element.title)
|
||||
self.errors.append(self.home_1, "Expected title is not shown, '%s' is instead!" % mention_element.title)
|
||||
if not mention_element.unread_indicator.is_element_displayed():
|
||||
self.errors.append("No unread dot is shown on activity center element (mention)!")
|
||||
self.errors.append(self.home_1, "No unread dot is shown on activity center element (mention)!")
|
||||
if mention_element.message_body.text != '@%s' % self.username_1:
|
||||
self.errors.append(
|
||||
"Mention body in activity center does not match expected, it is %s!" % mention_element.message_body.text)
|
||||
self.home_1, "Mention body in activity center does not match expected, it is %s!"
|
||||
% mention_element.message_body.text)
|
||||
|
||||
self.home_1.just_fyi("Tap on it and check redirect to channel")
|
||||
mention_element.click()
|
||||
if not self.channel_1.chat_element_by_text(self.username_1).is_element_displayed():
|
||||
self.errors.append("Was not redirected to chat after tapping on mention!")
|
||||
self.errors.append(self.home_1, "Was not redirected to chat after tapping on mention!")
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(702958)
|
||||
@@ -465,13 +477,13 @@ class TestActivityMultipleDevicePRTwo(MultipleSharedDeviceTestCase):
|
||||
try:
|
||||
self.home_1.notifications_unread_badge.wait_for_visibility_of_element(120)
|
||||
except TimeoutException:
|
||||
self.errors.append("Unread indicator is not shown in notifications")
|
||||
self.errors.append(self.home_1, "Unread indicator is not shown in notifications")
|
||||
self.home_1.open_activity_center_button.click()
|
||||
reply_element = self.home_1.get_element_from_activity_center_view(self.username_2)
|
||||
if reply_element.title.text != 'Join request':
|
||||
self.errors.append("Expected title is not shown, '%s' is instead!" % reply_element.title)
|
||||
self.errors.append(self.home_1, "Expected title is not shown, '%s' is instead!" % reply_element.title)
|
||||
if not reply_element.unread_indicator.is_element_displayed():
|
||||
self.errors.append("No unread dot is shown on activity center element!")
|
||||
self.errors.append(self.home_1, "No unread dot is shown on activity center element!")
|
||||
reply_element.title.swipe_right_on_element(width_percentage=2.5)
|
||||
self.home_1.activity_notification_swipe_button.click()
|
||||
self.home_1.close_activity_centre.click()
|
||||
@@ -479,5 +491,5 @@ class TestActivityMultipleDevicePRTwo(MultipleSharedDeviceTestCase):
|
||||
self.home_2.just_fyi("Checking that community appeared on the list")
|
||||
if not self.home_2.element_by_text_part(community_name).is_element_displayed(30):
|
||||
self.errors.append(
|
||||
"Community is not appeared in the list after accepting admin request from activity centre")
|
||||
self.home_2, "Community is not appeared in the list after accepting admin request from activity centre")
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@@ -18,6 +18,7 @@ from urllib3.exceptions import MaxRetryError, ProtocolError
|
||||
from support.api.network_api import NetworkApi
|
||||
from tests import test_suite_data, start_threads, pytest_config_global, transl
|
||||
from tests.conftest import github_report, run_name, lambda_test_username, lambda_test_access_key
|
||||
from views.base_view import BaseView
|
||||
|
||||
executor_lambda_test = 'https://%s:%s@mobile-hub.lambdatest.com/wd/hub' % (lambda_test_username, lambda_test_access_key)
|
||||
|
||||
@@ -164,12 +165,14 @@ class Driver(webdriver.Remote):
|
||||
self.execute_script("lambda-hook: %s" % str(data).replace("'", "\""))
|
||||
|
||||
|
||||
class Errors(object):
|
||||
class Errors:
|
||||
def __init__(self):
|
||||
self.errors = list()
|
||||
|
||||
def append(self, text=str()):
|
||||
self.errors.append(text)
|
||||
def append(self, view: BaseView, text: str):
|
||||
error_text = "Device %s: %s" % (view.driver.number, text)
|
||||
self.errors.append(error_text)
|
||||
view.driver.log_event("appium", error_text)
|
||||
|
||||
def verify_no_errors(self):
|
||||
if self.errors:
|
||||
|
||||
@@ -32,7 +32,8 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
for home in (self.home_1, self.home_2):
|
||||
home.navigate_back_to_home_view()
|
||||
home.chats_tab.click()
|
||||
self.home_1.add_contact(self.public_key_2)
|
||||
self.username_1 = "user_1"
|
||||
self.home_1.add_contact(public_key=self.public_key_2, username=self.username_1)
|
||||
|
||||
self.home_2.just_fyi("Accepting contact request from activity centre")
|
||||
self.home_2.handle_contact_request(self.username_1)
|
||||
@@ -89,13 +90,13 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
if not self.chat_1.user_list_element_by_name(
|
||||
self.username_1).is_element_displayed() or not self.chat_1.user_list_element_by_name(
|
||||
self.username_2).is_element_displayed():
|
||||
self.errors.append("Incorrect users are shown for 'love' reaction.")
|
||||
self.errors.append(self.chat_1, "Incorrect users are shown for 'love' reaction.")
|
||||
|
||||
self.chat_1.authors_for_reaction(emoji="thumbs-up").double_click()
|
||||
if not self.chat_1.user_list_element_by_name(
|
||||
self.username_1).is_element_displayed() or self.chat_1.user_list_element_by_name(
|
||||
self.username_2).is_element_displayed():
|
||||
self.errors.append("Incorrect users are shown for 'thumbs-up' reaction.")
|
||||
self.errors.append(self.chat_1, "Incorrect users are shown for 'thumbs-up' reaction.")
|
||||
self.chat_1.driver.press_keycode(4)
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
@@ -111,17 +112,18 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
self.chat_1.send_message(emoji.emojize(emoji_name))
|
||||
for chat in self.chat_1, self.chat_2:
|
||||
if not chat.chat_element_by_text(emoji_unicode).is_element_displayed():
|
||||
self.errors.append('Message with emoji was not sent or received in 1-1 chat')
|
||||
self.errors.append(chat, 'Message with emoji was not sent or received in 1-1 chat')
|
||||
self.chat_1.quote_message(emoji_unicode)
|
||||
actual_text = self.chat_1.quote_username_in_message_input.text
|
||||
if actual_text != "You":
|
||||
self.errors.append(
|
||||
self.chat_1,
|
||||
"'You' is not displayed in reply quote snippet replying to own message, '%s' instead" % actual_text)
|
||||
|
||||
self.chat_1.just_fyi("Clear quote and check there is not snippet anymore")
|
||||
self.chat_1.cancel_reply_button.click()
|
||||
if self.chat_1.cancel_reply_button.is_element_displayed():
|
||||
self.errors.append("Message quote kept in public chat input after it was cancelled")
|
||||
self.errors.append(self.chat_1, "Message quote kept in public chat input after it was cancelled")
|
||||
|
||||
self.chat_1.just_fyi("Send reply")
|
||||
self.chat_1.quote_message(emoji_unicode)
|
||||
@@ -130,7 +132,7 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
|
||||
self.chat_1.just_fyi("Receiver verifies received reply...")
|
||||
if self.chat_2.chat_element_by_text(reply_to_message_from_sender).replied_message_text != emoji_unicode:
|
||||
self.errors.append("No reply received in 1-1 chat")
|
||||
self.errors.append(self.chat_2, "No reply received in 1-1 chat")
|
||||
else:
|
||||
self.chat_2.just_fyi("Device 2 sets a reaction on the message reply. Device 1 checks the reaction")
|
||||
self.chat_1.set_reaction(reply_to_message_from_sender)
|
||||
@@ -138,7 +140,7 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
self.chat_1.chat_element_by_text(
|
||||
reply_to_message_from_sender).emojis_below_message().wait_for_element_text(1)
|
||||
except Failed:
|
||||
self.errors.append("Reply message reaction is not shown for the sender")
|
||||
self.errors.append(self.chat_1, "Reply message reaction is not shown for the sender")
|
||||
|
||||
self.home_1.just_fyi("Check that link can be opened and replied from 1-1 chat")
|
||||
reply = 'reply to link'
|
||||
@@ -149,14 +151,15 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
self.chat_2.send_message(reply)
|
||||
replied_message = self.chat_1.chat_element_by_text(reply)
|
||||
if replied_message.replied_message_text != url_message:
|
||||
self.errors.append("Reply for '%s' not present in message received in public chat" % url_message)
|
||||
self.errors.append(self.chat_1,
|
||||
"Reply for '%s' not present in message received in public chat" % url_message)
|
||||
|
||||
self.chat_2.just_fyi("Device 2 sets a reaction on the message with a link. Device 1 checks the reaction")
|
||||
self.chat_2.set_reaction(url_message)
|
||||
try:
|
||||
self.chat_1.chat_element_by_text(url_message).emojis_below_message().wait_for_element_text(1)
|
||||
except (Failed, NoSuchElementException):
|
||||
self.errors.append("Link message reaction is not shown for the sender")
|
||||
self.errors.append(self.chat_1, "Link message reaction is not shown for the sender")
|
||||
|
||||
self.home_2.just_fyi("Check 'Open in Status' option")
|
||||
# url_to_open = 'http://status.app'
|
||||
@@ -169,15 +172,15 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
try:
|
||||
self.chat_2.wait_for_current_package_to_be('com.android.chrome')
|
||||
except TimeoutException:
|
||||
self.errors.append('URL was not opened from 1-1 chat')
|
||||
self.errors.append(self.chat_2, 'URL was not opened from 1-1 chat')
|
||||
else:
|
||||
self.chat_2.element_by_text("No thanks").click_if_shown()
|
||||
text_element = self.chat_2.element_by_text("a free (libre) open source, mobile OS for Ethereum")
|
||||
sign_in_button = Button(self.chat_2.driver, xpath="//android.view.View[@content-desc='Sign in']")
|
||||
if not text_element.is_element_displayed() or not sign_in_button.is_element_displayed():
|
||||
self.errors.append('URL was not opened from 1-1 chat')
|
||||
self.errors.append(self.chat_2, 'URL was not opened from 1-1 chat')
|
||||
else:
|
||||
self.errors.append("Message with URL was not received")
|
||||
self.errors.append(self.chat_2, "Message with URL was not received")
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@@ -212,14 +215,15 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
else:
|
||||
expected_text = "You" if message == self.message_2 else self.username_1
|
||||
if text != expected_text:
|
||||
self.errors.append(
|
||||
"Pinned by '%s' doesn't match expected '%s' for user %s" % (
|
||||
text, expected_text, chat_number + 1)
|
||||
)
|
||||
self.errors.append(chat,
|
||||
"Pinned by '%s' doesn't match expected '%s' for user %s" % (
|
||||
text, expected_text, chat_number + 1)
|
||||
)
|
||||
else:
|
||||
self.errors.append(
|
||||
"Message '%s' is missed on Pinned messages list for user %s" % (message, chat_number + 1)
|
||||
)
|
||||
self.errors.append(chat,
|
||||
"Message '%s' is missed on Pinned messages list for user %s" % (
|
||||
message, chat_number + 1)
|
||||
)
|
||||
chat.click_system_back_button()
|
||||
|
||||
self.home_1.just_fyi("Check that Device1 can not pin more than 3 messages and 'Unpin' dialog appears")
|
||||
@@ -232,22 +236,23 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
self.chat_1.view_pinned_messages_button.click_until_presence_of_element(self.chat_1.pinned_messages_list)
|
||||
if self.chat_1.pinned_messages_list.get_pinned_messages_number() > 3 \
|
||||
or self.chat_1.pinned_messages_list.message_element_by_text(self.message_4).is_element_displayed():
|
||||
self.errors.append("Can pin more than 3 messages in chat")
|
||||
self.errors.append(self.chat_1, "Can pin more than 3 messages in chat")
|
||||
else:
|
||||
unpin_element = self.chat_1.element_by_translation_id('unpin-from-chat')
|
||||
self.chat_1.pinned_messages_list.message_element_by_text(self.message_2).long_press_without_release()
|
||||
self.home_1.just_fyi("Unpin one message so that another could be pinned")
|
||||
unpin_element.click_until_absense_of_element(desired_element=unpin_element)
|
||||
self.chat_1.pin_message(self.message_4, 'pin-to-chat')
|
||||
if not (self.chat_1.chat_element_by_text(self.message_4).pinned_by_label.is_element_displayed(30) and
|
||||
self.chat_2.chat_element_by_text(self.message_4).pinned_by_label.is_element_displayed(30)):
|
||||
self.errors.append("Message 4 is not pinned in chat after unpinning previous one")
|
||||
for chat in self.chat_1, self.chat_2:
|
||||
if not chat.chat_element_by_text(self.message_4).pinned_by_label.is_element_displayed(30):
|
||||
self.errors.append(chat, "Message 4 is not pinned in chat after unpinning previous one")
|
||||
|
||||
self.home_1.just_fyi("Check pinned messages are visible in Pinned panel for both users")
|
||||
for chat_number, chat in enumerate([self.chat_1, self.chat_2]):
|
||||
count = chat.pinned_messages_count.text
|
||||
if count != '3':
|
||||
self.errors.append("Pinned messages count is %s but should be 3 for user %s" % (count, chat_number + 1))
|
||||
self.errors.append(chat,
|
||||
"Pinned messages count is %s but should be 3 for user %s" % (count, chat_number + 1))
|
||||
|
||||
self.home_1.just_fyi("Unpin one message and check it's unpinned for another user")
|
||||
self.chat_2.tap_by_coordinates(500, 100)
|
||||
@@ -268,7 +273,7 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
chat.pinned_messages_count.wait_for_element_text(text='2', wait_time=20)
|
||||
except Failed:
|
||||
self.errors.append(
|
||||
"Pinned messages count is not 2 after unpinning the last pinned message for user %s" % (
|
||||
chat, "Pinned messages count is not 2 after unpinning the last pinned message for user %s" % (
|
||||
chat_number + 1)
|
||||
)
|
||||
self.errors.verify_no_errors()
|
||||
@@ -293,7 +298,7 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
for message in messages:
|
||||
self.chat_2.send_message(message)
|
||||
if not self.chat_1.chat_element_by_text(message).is_element_displayed(30):
|
||||
self.errors.append("Message with text '%s' was not received" % message)
|
||||
self.errors.append(self.chat_1, "Message with text '%s' was not received" % message)
|
||||
|
||||
self.chat_2.just_fyi("Checking updated member photo, timestamp and username on message")
|
||||
self.chat_2.hide_keyboard_if_shown()
|
||||
@@ -301,13 +306,15 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
timestamp = self.chat_2.chat_element_by_text(messages[0]).timestamp
|
||||
sent_time_variants = self.chat_2.convert_device_time_to_chat_timestamp()
|
||||
if timestamp not in sent_time_variants:
|
||||
self.errors.append(
|
||||
'Timestamp on message %s does not correspond expected %s' % (timestamp, sent_time_variants))
|
||||
self.errors.append(self.chat_2,
|
||||
'Timestamp on message %s does not correspond expected %s' % (
|
||||
timestamp, sent_time_variants))
|
||||
except NoSuchElementException:
|
||||
self.errors.append("No timestamp on message %s" % messages[0])
|
||||
self.errors.append(self.chat_2, "No timestamp on message %s" % messages[0])
|
||||
for message in [messages[1], messages[2]]:
|
||||
if self.chat_2.chat_element_by_text(message).member_photo.is_element_displayed():
|
||||
self.errors.append('%s is not stack to 1st(they are sent in less than 5 minutes)!' % message)
|
||||
self.errors.append(self.chat_2,
|
||||
'%s is not stack to 1st(they are sent in less than 5 minutes)!' % message)
|
||||
|
||||
self.chat_1.just_fyi("Sending message")
|
||||
message = 'profile_photo'
|
||||
@@ -319,7 +326,7 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
self.home_2.get_chat(self.username_1).click()
|
||||
if self.chat_2.chat_element_by_text(message).member_photo.is_element_differs_from_template(
|
||||
"profile_image_in_1_1_chat.png", diff=7):
|
||||
self.errors.append("Image of user in 1-1 chat is too different from template!")
|
||||
self.errors.append(self.chat_2, "Image of user in 1-1 chat is too different from template!")
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(702813)
|
||||
@@ -371,9 +378,10 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
|
||||
self.device_1.just_fyi("Checks there are no PN after message was seen")
|
||||
[home.open_notification_bar() for home in self.homes]
|
||||
if (self.device_2.element_by_text_part(message).is_element_displayed()
|
||||
or self.device_1.element_by_text_part(emoji_unicode).is_element_displayed()):
|
||||
self.errors.append("PN are keep staying after message was seen by user")
|
||||
if self.device_2.element_by_text_part(message).is_element_displayed():
|
||||
self.errors.append(self.chat_2, "PN are keep staying after message '%s' was seen by user" % message)
|
||||
if self.device_1.element_by_text_part(emoji_unicode).is_element_displayed():
|
||||
self.errors.append(self.chat_1, "PN are keep staying after message '%s' was seen by user" % emoji_unicode)
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(702855)
|
||||
@@ -393,7 +401,7 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
message_text_after_edit = message_after_edit_1_1 + ' (Edited)'
|
||||
chat_element = self.chat_1.chat_element_by_text(message_text_after_edit)
|
||||
if not chat_element.is_element_displayed(30):
|
||||
self.errors.append('No edited message in 1-1 chat displayed')
|
||||
self.errors.append(self.chat_1, 'No edited message in 1-1 chat displayed')
|
||||
else:
|
||||
self.device_1.just_fyi("Device 1 sets a reaction on the edited message. Device 2 checks the reaction")
|
||||
self.chat_1.set_reaction(message_text_after_edit)
|
||||
@@ -401,7 +409,7 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
self.chat_1.chat_element_by_text(
|
||||
message_text_after_edit).emojis_below_message().wait_for_element_text(1)
|
||||
except Failed:
|
||||
self.errors.append("Message reaction is not shown for the sender")
|
||||
self.errors.append(self.chat_1, "Message reaction is not shown for the sender")
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(703391)
|
||||
@@ -425,7 +433,7 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
self.chat_2.chat_element_by_text(image_description).wait_for_visibility_of_element(30)
|
||||
if not self.chat_2.chat_element_by_text(
|
||||
image_description).image_in_message.is_element_image_similar_to_template('image_1_chat_view.png'):
|
||||
self.errors.append("Not expected image is shown to the receiver.")
|
||||
self.errors.append(self.chat_2, "Not expected image is shown to the receiver.")
|
||||
|
||||
for chat in self.chat_1, self.chat_2:
|
||||
chat.just_fyi("Open the image and share it")
|
||||
@@ -437,8 +445,9 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
try:
|
||||
chat.wait_for_current_package_to_be('com.google.android.apps.docs')
|
||||
except TimeoutException:
|
||||
self.errors.append(
|
||||
"%s can't share an image via Gmail." % ("Sender" if chat is self.chat_1 else "Receiver"))
|
||||
self.errors.append(chat,
|
||||
"%s can't share an image via Gmail." % (
|
||||
"Sender" if chat is self.chat_1 else "Receiver"))
|
||||
chat.navigate_back_to_chat_view()
|
||||
|
||||
for chat in self.chat_1, self.chat_2:
|
||||
@@ -452,10 +461,10 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
toast_element_text = toast_element.text
|
||||
if toast_element_text != chat.get_translation_by_key("photo-saved"):
|
||||
self.errors.append(
|
||||
"Shown message '%s' doesn't match expected '%s' after saving an image for %s." % (
|
||||
chat, "Shown message '%s' doesn't match expected '%s' after saving an image for %s." % (
|
||||
toast_element_text, chat.get_translation_by_key("photo-saved"), device_name))
|
||||
else:
|
||||
self.errors.append("Message about saving a photo is not shown for %s." % device_name)
|
||||
self.errors.append(chat, "Message about saving a photo is not shown for %s." % device_name)
|
||||
chat.navigate_back_to_chat_view()
|
||||
|
||||
for chat in self.chat_1, self.chat_2:
|
||||
@@ -463,8 +472,9 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
chat.show_images_button.click()
|
||||
chat.allow_all_button.click_if_shown()
|
||||
if not chat.get_image_by_index(0).is_element_image_similar_to_template("image_1_gallery_view.png"):
|
||||
self.errors.append(
|
||||
"Image is not saved to gallery for %s." % ("sender" if chat is self.chat_1 else "receiver"))
|
||||
self.errors.append(chat,
|
||||
"Image is not saved to gallery for %s." % (
|
||||
"sender" if chat is self.chat_1 else "receiver"))
|
||||
chat.click_system_back_button()
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
@@ -490,7 +500,7 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
chat_1_element.long_press_without_release()
|
||||
for action in ("edit", "delete-for-everyone"):
|
||||
if self.chat_1.element_by_translation_id(action).is_element_displayed():
|
||||
self.errors.append('Option to %s someone else message available!' % action)
|
||||
self.errors.append(self.chat_1, 'Option to %s someone else message available!' % action)
|
||||
self.home_1.tap_by_coordinates(500, 100)
|
||||
|
||||
self.device_2.just_fyi("Delete message for me and check it is only deleted for the author")
|
||||
@@ -500,23 +510,23 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
self.chat_2.chat_element_by_text(message_to_delete_for_me).wait_for_status_to_be("Delivered", timeout)
|
||||
self.chat_2.delete_message_in_chat(message_to_delete_for_me, everyone=False)
|
||||
except TimeoutException:
|
||||
self.errors.append("Message status was not changed to 'Delivered' after %s s" % timeout)
|
||||
self.errors.append(self.chat_2, "Message status was not changed to 'Delivered' after %s s" % timeout)
|
||||
else:
|
||||
if not self.chat_2.chat_element_by_text(message_to_delete_for_me).is_element_disappeared(20):
|
||||
self.errors.append("Deleted for me message is shown in chat for the author of message")
|
||||
self.errors.append(self.chat_2, "Deleted for me message is shown in chat for the author of message")
|
||||
if not self.chat_2.element_by_translation_id('message-deleted-for-you').is_element_displayed(20):
|
||||
self.errors.append("System message about deletion for you is not displayed")
|
||||
self.errors.append(self.chat_2, "System message about deletion for you is not displayed")
|
||||
if not self.chat_1.chat_element_by_text(message_to_delete_for_me).is_element_displayed(20):
|
||||
self.errors.append("Deleted for me message is deleted for both users")
|
||||
self.errors.append(self.chat_1, "Deleted for me message is deleted for both users")
|
||||
|
||||
self.device_2.just_fyi("Delete message for everyone and check it is not shown in chat preview on home")
|
||||
self.chat_2.delete_message_in_chat(message_after_edit_1_1)
|
||||
for chat in (self.chat_2, self.chat_1):
|
||||
if chat.chat_element_by_text(message_after_edit_1_1).is_element_displayed(30):
|
||||
self.errors.append("Deleted message is shown in chat view for 1-1 chat")
|
||||
self.errors.append(chat, "Deleted message is shown in chat view for 1-1 chat")
|
||||
self.chat_1.navigate_back_to_home_view()
|
||||
if self.home_1.element_by_text(message_after_edit_1_1).is_element_displayed(30):
|
||||
self.errors.append("Deleted message is shown on chat element on home screen")
|
||||
self.errors.append(self.home_1, "Deleted message is shown on chat element on home screen")
|
||||
|
||||
self.device_2.just_fyi("Send one more message and check that PN will be deleted with message deletion")
|
||||
message_to_delete = 'DELETE ME'
|
||||
@@ -527,12 +537,12 @@ class TestOneToOneChatMultipleSharedDevicesNewUi(MultipleSharedDeviceTestCase):
|
||||
if not self.home_1.get_pn(message_to_delete):
|
||||
self.home_1.click_system_back_button()
|
||||
self.device_2.driver.activate_app(app_package)
|
||||
self.errors.append("Push notification doesn't appear")
|
||||
self.errors.append(self.home_1, "Push notification doesn't appear")
|
||||
self.chat_2.delete_message_in_chat(message_to_delete)
|
||||
pn_to_disappear = self.home_1.get_pn(message_to_delete)
|
||||
if pn_to_disappear:
|
||||
if not pn_to_disappear.is_element_disappeared(90):
|
||||
self.errors.append("Push notification was not removed after initial message deletion")
|
||||
self.errors.append(self.home_1, "Push notification was not removed after initial message deletion")
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
|
||||
@@ -580,9 +590,9 @@ class TestOneToOneChatMultipleSharedDevicesNewUiTwo(MultipleSharedDeviceTestCase
|
||||
chat_element = chat.chat_element_by_text(image_description)
|
||||
if chat_element.is_element_displayed(30):
|
||||
if not chat_element.image_in_message.is_element_image_similar_to_template('saucelabs_camera_image.png'):
|
||||
self.errors.append("Not expected image is shown to the %s." % chat_name)
|
||||
self.errors.append(chat, "Not expected image is shown to the %s." % chat_name)
|
||||
else:
|
||||
self.errors.append("Message with camera image is not shown in chat for %s" % chat_name)
|
||||
self.errors.append(chat, "Message with camera image is not shown in chat for %s" % chat_name)
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(702783)
|
||||
@@ -608,7 +618,7 @@ class TestOneToOneChatMultipleSharedDevicesNewUiTwo(MultipleSharedDeviceTestCase
|
||||
self.chat_2.send_message(message_1)
|
||||
status = self.chat_2.chat_element_by_text(message_1).status
|
||||
if not (status == 'Sending' or status == 'Sent'):
|
||||
self.errors.append('Message status is not "Sending", it is "%s"!' % status)
|
||||
self.errors.append(self.chat_2, 'Message status is not "Sending", it is "%s"!' % status)
|
||||
|
||||
self.home_2.just_fyi('Device2 goes back online and checks that status of the message is changed to "delivered"')
|
||||
for home in self.homes:
|
||||
@@ -616,13 +626,13 @@ class TestOneToOneChatMultipleSharedDevicesNewUiTwo(MultipleSharedDeviceTestCase
|
||||
|
||||
self.home_1.just_fyi('Device1 goes back online and checks that 1-1 chat will be fetched')
|
||||
if not self.chat_1.chat_element_by_text(message_1).is_element_displayed(120):
|
||||
self.errors.append("Message was not delivered after resending from offline")
|
||||
self.errors.append(self.chat_1, "Message was not delivered after resending from offline")
|
||||
|
||||
self.home_2.just_fyi('Device1 goes back online and checks that 1-1 chat will be fetched')
|
||||
try:
|
||||
self.chat_2.chat_element_by_text(message_1).wait_for_status_to_be(expected_status='Delivered', timeout=120)
|
||||
except TimeoutException as e:
|
||||
self.errors.append('%s after back up online!' % e.msg)
|
||||
self.errors.append(self.chat_2, '%s after back up online!' % e.msg)
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(703496)
|
||||
@@ -636,33 +646,35 @@ class TestOneToOneChatMultipleSharedDevicesNewUiTwo(MultipleSharedDeviceTestCase
|
||||
self.chat_2.send_message(muted_message)
|
||||
chat = self.home_1.get_chat(self.username_2)
|
||||
if chat.new_messages_counter.is_element_displayed(30) or self.home_1.chats_tab.counter.is_element_displayed(10):
|
||||
self.errors.append("New messages counter is shown after mute")
|
||||
self.errors.append(self.home_1, "New messages counter is shown after mute")
|
||||
if not chat.chat_preview.text.startswith(muted_message):
|
||||
self.errors.append("Message text '%s' is not shown in chat preview after mute" % muted_message)
|
||||
self.errors.append(self.home_1, "Message text '%s' is not shown in chat preview after mute" % muted_message)
|
||||
chat.click()
|
||||
if not self.chat_1.chat_element_by_text(muted_message).is_element_displayed(30):
|
||||
self.errors.append("Message '%s' is not shown in chat for receiver after mute" % muted_message)
|
||||
self.errors.append(self.chat_1, "Message '%s' is not shown in chat for receiver after mute" % muted_message)
|
||||
|
||||
self.chat_1.just_fyi("Unmute chat")
|
||||
self.chat_1.navigate_back_to_home_view()
|
||||
chat.long_press_without_release()
|
||||
if self.home_1.mute_chat_button.text != transl["unmute-chat"]:
|
||||
self.errors.append("Chat is not muted")
|
||||
self.errors.append(self.home_1, "Chat is not muted")
|
||||
expected_text = "Muted until you turn it back on"
|
||||
if not self.home_1.element_by_text(expected_text).is_element_displayed():
|
||||
self.errors.append("Text '%s' is not shown for muted chat" % expected_text)
|
||||
self.errors.append(self.home_1, "Text '%s' is not shown for muted chat" % expected_text)
|
||||
self.home_1.mute_chat_button.double_click()
|
||||
|
||||
unmuted_message = "after unmute"
|
||||
self.chat_2.send_message(unmuted_message)
|
||||
if not chat.new_messages_counter.is_element_displayed(
|
||||
30) or not self.home_1.chats_tab.counter.is_element_displayed(10):
|
||||
self.errors.append("New messages counter is not shown after unmute")
|
||||
self.errors.append(self.home_1, "New messages counter is not shown after unmute")
|
||||
if not chat.chat_preview.text.startswith(unmuted_message):
|
||||
self.errors.append("Message text '%s' is not shown in chat preview after unmute" % unmuted_message)
|
||||
self.errors.append(self.home_1,
|
||||
"Message text '%s' is not shown in chat preview after unmute" % unmuted_message)
|
||||
chat.click()
|
||||
if not self.chat_1.chat_element_by_text(unmuted_message).is_element_displayed(30):
|
||||
self.errors.append("Message '%s' is not shown in chat for receiver after unmute" % unmuted_message)
|
||||
self.errors.append(self.chat_1,
|
||||
"Message '%s' is not shown in chat for receiver after unmute" % unmuted_message)
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@@ -677,7 +689,7 @@ class TestOneToOneChatMultipleSharedDevicesNewUiTwo(MultipleSharedDeviceTestCase
|
||||
for element in self.chat_2.chat_element_by_text(text='').message_text_content.find_elements():
|
||||
chat_history.append(element.text)
|
||||
if not chat_history:
|
||||
self.errors.append("No chat history was loaded")
|
||||
self.errors.append(self.chat_2, "No chat history was loaded")
|
||||
|
||||
self.home_2.just_fyi("Deleting chat via delete button and check it will not reappear after relaunching app")
|
||||
self.home_2.navigate_back_to_home_view()
|
||||
@@ -685,10 +697,12 @@ class TestOneToOneChatMultipleSharedDevicesNewUiTwo(MultipleSharedDeviceTestCase
|
||||
self.home_2.delete_chat_long_press(username=self.username_1)
|
||||
chat = self.home_2.get_chat_from_home_view(self.username_1)
|
||||
if chat.is_element_displayed():
|
||||
self.errors.append("Deleted '%s' chat is shown, but the chat has been deleted" % self.username_1)
|
||||
self.errors.append(self.chat_2,
|
||||
"Deleted '%s' chat is shown, but the chat has been deleted" % self.username_1)
|
||||
self.home_2.reopen_app(user_name=self.username_2)
|
||||
if chat.is_element_displayed(15):
|
||||
self.errors.append(
|
||||
self.chat_2,
|
||||
"Deleted chat '%s' is shown after re-login, but the chat has been deleted" % self.username_1)
|
||||
chat.click()
|
||||
else:
|
||||
@@ -701,5 +715,6 @@ class TestOneToOneChatMultipleSharedDevicesNewUiTwo(MultipleSharedDeviceTestCase
|
||||
if not self.chat_2.chat_element_by_text(message_text).is_element_displayed():
|
||||
lost_messages.append(message_text)
|
||||
if lost_messages:
|
||||
self.errors.append("Message(s) missed in 1-1 chat after deleting the chat and relogin: %s" % lost_messages)
|
||||
self.errors.append(self.chat_2,
|
||||
"Message(s) missed in 1-1 chat after deleting the chat and relogin: %s" % lost_messages)
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@@ -95,14 +95,14 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
|
||||
if pn:
|
||||
pn.click()
|
||||
else:
|
||||
self.errors.append("No PN was received on new message for message in group chat")
|
||||
self.errors.append(self.homes[0], "No PN was received on new message for message in group chat")
|
||||
self.homes[0].click_system_back_button()
|
||||
self.homes[0].get_chat(self.chat_name).click()
|
||||
|
||||
self.chats[1].just_fyi('Check message status and message delivery')
|
||||
self.chats[1].chat_element_by_text(message_to_admin).wait_for_status_to_be('Delivered', timeout=120)
|
||||
if not self.chats[0].chat_element_by_text(message_to_admin).is_element_displayed(30):
|
||||
self.errors.append('Message %s was not received by admin' % message_to_admin)
|
||||
self.errors.append(self.chats[0], 'Message %s was not received by admin' % message_to_admin)
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(703202)
|
||||
@@ -139,19 +139,19 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
|
||||
if not self.chats[0].user_list_element_by_name(
|
||||
self.usernames[1]).is_element_displayed() or not self.chats[0].user_list_element_by_name(
|
||||
self.usernames[2]).is_element_displayed():
|
||||
self.errors.append("Incorrect users are shown for 'thumbs-up' reaction.")
|
||||
self.errors.append(self.chats[0], "Incorrect users are shown for 'thumbs-up' reaction.")
|
||||
|
||||
self.chats[0].authors_for_reaction(emoji="love").double_click()
|
||||
if not self.chats[0].user_list_element_by_name(
|
||||
self.usernames[1]).is_element_displayed() or self.chats[0].user_list_element_by_name(
|
||||
self.usernames[2]).is_element_displayed():
|
||||
self.errors.append("Incorrect users are shown for 'love' reaction.")
|
||||
self.errors.append(self.chats[0], "Incorrect users are shown for 'love' reaction.")
|
||||
|
||||
self.chats[0].authors_for_reaction(emoji="laugh").click()
|
||||
if self.chats[0].user_list_element_by_name(
|
||||
self.usernames[1]).is_element_displayed() or not self.chats[0].user_list_element_by_name(
|
||||
self.usernames[2]).is_element_displayed():
|
||||
self.errors.append("Incorrect users are shown for 'laugh' reaction.")
|
||||
self.errors.append(self.chats[0], "Incorrect users are shown for 'laugh' reaction.")
|
||||
|
||||
self.chats[0].just_fyi("Admin opens member_2 profile")
|
||||
self.chats[0].user_list_element_by_name(self.usernames[2]).click()
|
||||
@@ -159,11 +159,12 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
|
||||
username_shown = self.chats[0].get_profile_view().contact_name_text.text
|
||||
if username_shown != self.usernames[2]:
|
||||
self.errors.append(
|
||||
self.chats[0],
|
||||
"Incorrect profile is opened from the list of reactions, username is %s but expected to be %s" % (
|
||||
username_shown, self.usernames[2])
|
||||
)
|
||||
except NoSuchElementException:
|
||||
self.errors.append("User profile was not opened from the list of reactions")
|
||||
self.errors.append(self.chats[0], "User profile was not opened from the list of reactions")
|
||||
self.chats[0].navigate_back_to_chat_view()
|
||||
|
||||
self.chats[1].just_fyi("Member_1 removes 'thumbs-up' reaction and adds 'sad' one")
|
||||
@@ -183,8 +184,9 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
|
||||
chat_element.emojis_below_message(emoji="love").wait_for_element_text(1)
|
||||
chat_element.emojis_below_message(emoji="sad").wait_for_element_text(2)
|
||||
except (Failed, NoSuchElementException):
|
||||
self.errors.append(
|
||||
"Incorrect reactions count for %s after changing the reactions" % self.usernames[chat_view_index])
|
||||
self.errors.append(self.chats[chat_view_index],
|
||||
"Incorrect reactions count for %s after changing the reactions" % self.usernames[
|
||||
chat_view_index])
|
||||
|
||||
self.loop.run_until_complete(run_in_parallel((
|
||||
(_check_reactions_count_after_change, {'chat_view_index': 0}),
|
||||
@@ -204,7 +206,7 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
|
||||
message_element.emojis_below_message(emoji="love").wait_for_element_text(1)
|
||||
message_element.emojis_below_message(emoji="sad").wait_for_element_text(2)
|
||||
except (Failed, NoSuchElementException):
|
||||
self.errors.append("Incorrect reactions count after relogin")
|
||||
self.errors.append(self.chats[0], "Incorrect reactions count after relogin")
|
||||
|
||||
for chat in self.chats[1], self.chats[2]:
|
||||
chat.just_fyi("Just making the session not to quit")
|
||||
@@ -215,19 +217,19 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
|
||||
if self.chats[0].user_list_element_by_name(
|
||||
self.usernames[1]).is_element_displayed() or not self.chats[0].user_list_element_by_name(
|
||||
self.usernames[2]).is_element_displayed():
|
||||
self.errors.append("Incorrect users are shown for 'thumbs-up' reaction after relogin.")
|
||||
self.errors.append(self.chats[0], "Incorrect users are shown for 'thumbs-up' reaction after relogin.")
|
||||
|
||||
self.chats[0].authors_for_reaction(emoji="love").double_click()
|
||||
if not self.chats[0].user_list_element_by_name(
|
||||
self.usernames[1]).is_element_displayed() or self.chats[0].user_list_element_by_name(
|
||||
self.usernames[2]).is_element_displayed():
|
||||
self.errors.append("Incorrect users are shown for 'love' reaction after relogin.")
|
||||
self.errors.append(self.chats[0], "Incorrect users are shown for 'love' reaction after relogin.")
|
||||
|
||||
self.chats[0].authors_for_reaction(emoji="sad").click()
|
||||
if not self.chats[0].user_list_element_by_name(
|
||||
self.usernames[1]).is_element_displayed() or not self.chats[0].user_list_element_by_name(
|
||||
self.usernames[2]).is_element_displayed():
|
||||
self.errors.append("Incorrect users are shown for 'laugh' reaction after relogin.")
|
||||
self.errors.append(self.chats[0], "Incorrect users are shown for 'laugh' reaction after relogin.")
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@@ -245,13 +247,13 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
|
||||
chat_element = self.chats[0].chat_element_by_text(image_description)
|
||||
chat_element.wait_for_visibility_of_element(60)
|
||||
if not chat_element.image_in_message.is_element_image_similar_to_template('image_2_chat_view.png'):
|
||||
self.errors.append("Not expected image is shown to the admin.")
|
||||
self.errors.append(self.chats[0], "Not expected image is shown to the admin.")
|
||||
|
||||
self.chats[2].just_fyi("Member_2 checks image message")
|
||||
chat_element = self.chats[2].chat_element_by_text(image_description)
|
||||
chat_element.wait_for_visibility_of_element(60)
|
||||
if not chat_element.image_in_message.is_element_image_similar_to_template('image_2_chat_view.png'):
|
||||
self.errors.append("Not expected image is shown to the member_2.")
|
||||
self.errors.append(self.chats[2], "Not expected image is shown to the member_2.")
|
||||
|
||||
self.chats[0].just_fyi("Admin opens the image and shares it")
|
||||
self.chats[0].chat_element_by_text(image_description).image_in_message.click()
|
||||
@@ -260,7 +262,7 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
|
||||
try:
|
||||
self.chats[0].wait_for_current_package_to_be('com.google.android.apps.docs')
|
||||
except TimeoutException:
|
||||
self.errors.append("Admin can't share an image via Gmail.")
|
||||
self.errors.append(self.chats[0], "Admin can't share an image via Gmail.")
|
||||
self.chats[0].navigate_back_to_chat_view()
|
||||
|
||||
self.chats[1].navigate_back_to_home_view()
|
||||
@@ -275,10 +277,11 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
|
||||
toast_element_text = toast_element.wait_for_visibility_of_element().text
|
||||
if toast_element_text != self.chats[2].get_translation_by_key("photo-saved"):
|
||||
self.errors.append(
|
||||
self.chats[2],
|
||||
"Shown message '%s' doesn't match expected '%s' after saving an image for member_2." % (
|
||||
toast_element_text, self.chats[2].get_translation_by_key("photo-saved")))
|
||||
except TimeoutException:
|
||||
self.errors.append("Message about saving a photo is not shown for member_2.")
|
||||
self.errors.append(self.chats[2], "Message about saving a photo is not shown for member_2.")
|
||||
self.chats[2].navigate_back_to_chat_view()
|
||||
|
||||
# workaround for app closed after navigating back from gallery
|
||||
@@ -292,7 +295,7 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
|
||||
self.chats[2].show_images_button.click()
|
||||
self.chats[2].allow_all_button.click_if_shown()
|
||||
if not self.chats[2].get_image_by_index(0).is_element_image_similar_to_template("image_2_gallery_view.png"):
|
||||
self.errors.append("Image is not saved to gallery for member_2.")
|
||||
self.errors.append(self.chats[2], "Image is not saved to gallery for member_2.")
|
||||
self.chats[2].navigate_back_to_home_view()
|
||||
|
||||
# workaround for app closed after navigating back from gallery
|
||||
@@ -333,7 +336,7 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
|
||||
if self.homes[0].element_by_text(message).is_element_displayed(30):
|
||||
break
|
||||
else:
|
||||
self.errors.append('Messages PN was not fetched from offline')
|
||||
self.errors.append(self.homes[0], 'Messages PN was not fetched from offline')
|
||||
self.homes[0].click_system_back_button()
|
||||
# workaround for app closed after opening notifications
|
||||
if not self.homes[0].chats_tab.is_element_displayed():
|
||||
@@ -346,7 +349,7 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
|
||||
self.chats[index].just_fyi("Check that messages are shown for user %s" % self.usernames[index])
|
||||
for message_text in (message_1, message_2):
|
||||
if not self.chats[index].chat_element_by_text(message_text).is_element_displayed(30):
|
||||
self.errors.append('%s if not shown for device %s' % (message_text, index))
|
||||
self.errors.append(self.chats[index], '%s if not shown for device %s' % (message_text, index))
|
||||
|
||||
self.loop.run_until_complete(run_in_parallel((
|
||||
(_check_messages, {'index': 0}),
|
||||
@@ -367,14 +370,14 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
|
||||
|
||||
self.chats[0].send_message(self.message_1)
|
||||
self.chats[0].pin_message(self.message_1, "pin-to-chat")
|
||||
if not (self.chats[0].chat_element_by_text(self.message_1).pinned_by_label.is_element_displayed(30) and
|
||||
self.chats[1].chat_element_by_text(self.message_1).pinned_by_label.is_element_displayed(30)):
|
||||
self.errors.append("Message 1 is not pinned in group chat!")
|
||||
for chat in self.chats[0], self.chats[1]:
|
||||
if not chat.chat_element_by_text(self.message_1).pinned_by_label.is_element_displayed(30):
|
||||
self.errors.append(chat, "Message 1 is not pinned in group chat!")
|
||||
|
||||
self.chats[0].just_fyi("Check that non admin user can not unpin messages")
|
||||
self.chats[1].chat_element_by_text(self.message_1).long_press_without_release()
|
||||
if self.chats[1].element_by_translation_id("unpin-from-chat").is_element_displayed():
|
||||
self.errors.append("Unpin option is available for non-admin user")
|
||||
self.errors.append(self.chats[1], "Unpin option is available for non-admin user")
|
||||
self.chats[1].tap_by_coordinates(500, 100)
|
||||
self.chats[1].tap_by_coordinates(500, 100)
|
||||
|
||||
@@ -396,9 +399,9 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
|
||||
# here group_chat_1 should be changed to group_chat_2 after enabling the previous block
|
||||
self.chats[0].send_message(message)
|
||||
self.chats[0].pin_message(message, 'pin-to-chat')
|
||||
if not (self.chats[0].chat_element_by_text(message).pinned_by_label.is_element_displayed(30) and
|
||||
self.chats[1].chat_element_by_text(message).pinned_by_label.is_element_displayed(30)):
|
||||
self.errors.append("%s is not pinned in group chat!" % message)
|
||||
for chat in self.chats[0], self.chats[1]:
|
||||
if not chat.chat_element_by_text(message).pinned_by_label.is_element_displayed(30):
|
||||
self.errors.append(chat, "%s is not pinned in group chat!" % message)
|
||||
|
||||
self.chats[0].just_fyi("Check that a user can not pin more than 3 messages")
|
||||
self.chats[0].send_message(self.message_4)
|
||||
@@ -409,16 +412,17 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
|
||||
unpin_element.click_until_absense_of_element(desired_element=unpin_element)
|
||||
self.chats[0].chat_element_by_text(self.message_4).click()
|
||||
self.chats[0].pin_message(self.message_4, 'pin-to-chat')
|
||||
if not (self.chats[0].chat_element_by_text(self.message_4).pinned_by_label.is_element_displayed(30) and
|
||||
self.chats[1].chat_element_by_text(self.message_4).pinned_by_label.is_element_displayed(30)):
|
||||
self.errors.append("Message 4 is not pinned in group chat after unpinning previous one")
|
||||
for chat in self.chats[0], self.chats[1]:
|
||||
if not chat.chat_element_by_text(self.message_4).pinned_by_label.is_element_displayed(30):
|
||||
self.errors.append(chat, "Message 4 is not pinned in group chat after unpinning previous one")
|
||||
|
||||
def _check_pinned_messages(index):
|
||||
self.chats[index].just_fyi("Check pinned messages count and content for user %s" % self.usernames[index])
|
||||
count = self.chats[index].pinned_messages_count.text
|
||||
if count != '3':
|
||||
self.errors.append(
|
||||
"Pinned messages count %s doesn't match expected 3 for user %s" % (count, self.usernames[index]))
|
||||
self.errors.append(self.chats[index],
|
||||
"Pinned messages count %s doesn't match expected 3 for user %s" % (
|
||||
count, self.usernames[index]))
|
||||
self.chats[index].pinned_messages_count.click()
|
||||
for message_text in self.message_1, self.message_3, self.message_4:
|
||||
pinned_by = self.chats[index].pinned_messages_list.get_message_pinned_by_text(message_text)
|
||||
@@ -426,14 +430,15 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
|
||||
text = pinned_by.text.strip()
|
||||
expected_text = "You" if index == 0 else self.usernames[0]
|
||||
if text != expected_text:
|
||||
self.errors.append(
|
||||
"Pinned by '%s' doesn't match expected '%s' for user %s" % (
|
||||
text, expected_text, self.usernames[index])
|
||||
)
|
||||
self.errors.append(self.chats[index],
|
||||
"Pinned by '%s' doesn't match expected '%s' for user %s" % (
|
||||
text, expected_text, self.usernames[index])
|
||||
)
|
||||
else:
|
||||
self.errors.append(
|
||||
"Message '%s' is missed on Pinned messages list for user %s" % (message, self.usernames[index])
|
||||
)
|
||||
self.errors.append(self.chats[index],
|
||||
"Message '%s' is missed on Pinned messages list for user %s" % (
|
||||
message, self.usernames[index])
|
||||
)
|
||||
|
||||
self.loop.run_until_complete(run_in_parallel((
|
||||
(_check_pinned_messages, {'index': 0}),
|
||||
@@ -460,7 +465,7 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
|
||||
pytest.fail("Chat is not muted")
|
||||
current_text = self.homes[1].mute_chat_button.unmute_caption_text
|
||||
if current_text not in expected_texts:
|
||||
self.errors.append("Text '%s' is not shown for muted chat" % expected_texts[1])
|
||||
self.errors.append(self.homes[1], "Text '%s' is not shown for muted chat" % expected_texts[1])
|
||||
self.homes[1].click_system_back_button()
|
||||
try:
|
||||
initial_counter = int(self.homes[1].chats_tab.counter.text)
|
||||
@@ -474,20 +479,23 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
|
||||
|
||||
self.homes[1].just_fyi("Member 1 checks that chat is muted and message is received")
|
||||
if chat.new_messages_grey_dot.is_element_displayed(30):
|
||||
self.errors.append("New messages grey dot near chat name is shown after mute")
|
||||
self.errors.append(self.homes[1], "New messages grey dot near chat name is shown after mute")
|
||||
try:
|
||||
after_mute_counter = int(self.homes[1].chats_tab.counter.text)
|
||||
except NoSuchElementException:
|
||||
after_mute_counter = 0
|
||||
if after_mute_counter > initial_counter:
|
||||
self.errors.append("New messages counter near chats tab button is %s after mute, but should be %s" % (
|
||||
after_mute_counter, initial_counter))
|
||||
self.errors.append(self.homes[1],
|
||||
"New messages counter near chats tab button is %s after mute, but should be %s" % (
|
||||
after_mute_counter, initial_counter))
|
||||
if not chat.chat_preview.text.startswith("%s: %s" % (self.usernames[0], muted_message[:25])):
|
||||
self.errors.append("Message text '%s' is not shown in chat preview after mute" % muted_message)
|
||||
self.errors.append(self.homes[1],
|
||||
"Message text '%s' is not shown in chat preview after mute" % muted_message)
|
||||
chat.click()
|
||||
if not self.chats[1].chat_element_by_text(muted_message).is_element_displayed(30):
|
||||
self.errors.append(
|
||||
"Message '%s' is not shown in chat for %s (Member 1) after mute" % (muted_message, self.usernames[1]))
|
||||
self.errors.append(self.chats[1],
|
||||
"Message '%s' is not shown in chat for %s (Member 1) after mute" % (
|
||||
muted_message, self.usernames[1]))
|
||||
self.chats[1].navigate_back_to_home_view()
|
||||
|
||||
self.chats[1].just_fyi("Member 1 unmutes the chat")
|
||||
@@ -495,7 +503,7 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
|
||||
self.homes[1].mute_chat_button.double_click()
|
||||
chat.long_press_without_release()
|
||||
if self.homes[1].element_starts_with_text("Muted until").is_element_displayed():
|
||||
self.errors.append("Chat is still muted after being unmuted")
|
||||
self.errors.append(self.homes[1], "Chat is still muted after being unmuted")
|
||||
self.errors.verify_no_errors()
|
||||
if self.homes[1].mute_chat_button.is_element_displayed():
|
||||
self.homes[1].click_system_back_button()
|
||||
@@ -510,20 +518,22 @@ class TestGroupChatMultipleDeviceMergedNewUI(MultipleSharedDeviceTestCase):
|
||||
self.chats[2].send_message(unmuted_message)
|
||||
self.homes[1].just_fyi("Member 1 checks that chat is unmuted and message is received")
|
||||
if not chat.new_messages_grey_dot.is_element_displayed(30):
|
||||
self.errors.append("New messages counter near chat name is not shown after unmute")
|
||||
self.errors.append(self.homes[1], "New messages counter near chat name is not shown after unmute")
|
||||
try:
|
||||
after_mute_counter = int(self.homes[1].chats_tab.counter.text)
|
||||
except NoSuchElementException:
|
||||
after_mute_counter = 0
|
||||
if after_mute_counter != initial_counter:
|
||||
self.errors.append("New messages counter near chats tab button is %s after unmute, but should be %s" % (
|
||||
after_mute_counter, initial_counter + 1))
|
||||
self.errors.append(self.homes[1],
|
||||
"New messages counter near chats tab button is %s after unmute, but should be %s" % (
|
||||
after_mute_counter, initial_counter + 1))
|
||||
if not chat.chat_preview.text.startswith("%s: %s" % (self.usernames[2], unmuted_message)):
|
||||
self.errors.append("Message text '%s' is not shown in chat preview after unmute" % unmuted_message)
|
||||
self.errors.append(self.homes[1],
|
||||
"Message text '%s' is not shown in chat preview after unmute" % unmuted_message)
|
||||
chat.click()
|
||||
if not self.chats[1].chat_element_by_text(unmuted_message).is_element_displayed(30):
|
||||
self.errors.append(
|
||||
"Message '%s' is not shown in chat for %s (Member 1) after unmute" % (
|
||||
unmuted_message, self.usernames[1]))
|
||||
self.errors.append(self.chats[1],
|
||||
"Message '%s' is not shown in chat for %s (Member 1) after unmute" % (
|
||||
unmuted_message, self.usernames[1]))
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@@ -10,7 +10,7 @@ from selenium.common.exceptions import NoSuchElementException, TimeoutException,
|
||||
|
||||
from tests import marks, run_in_parallel, pytest_config_global, transl
|
||||
from tests.base_test_case import create_shared_drivers, MultipleSharedDeviceTestCase
|
||||
from views.chat_view import CommunityView, ChatView
|
||||
from views.chat_view import CommunityView
|
||||
from views.dbs.waku_backup import user as waku_user
|
||||
from views.sign_in_view import SignInView
|
||||
|
||||
@@ -61,6 +61,7 @@ class TestCommunityOneDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
actual_copied_text = self.channel.driver.get_clipboard_text()
|
||||
if actual_copied_text != message:
|
||||
self.errors.append(
|
||||
self.channel,
|
||||
'Message %s text was not copied in community channel, text in clipboard %s' % actual_copied_text)
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
@@ -103,9 +104,9 @@ class TestCommunityOneDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
try:
|
||||
current_text = self.home.unmute_community_button.unmute_caption_text
|
||||
if current_text not in expected_texts:
|
||||
self.errors.append("Text '%s' is not shown for muted community" % expected_texts[1])
|
||||
self.errors.append(self.home, "Text '%s' is not shown for muted community" % expected_texts[1])
|
||||
except NoSuchElementException:
|
||||
self.errors.append("Caption with text 'Muted until...' is not shown for muted community")
|
||||
self.errors.append(self.home, "Caption with text 'Muted until...' is not shown for muted community")
|
||||
self.home.click_system_back_button()
|
||||
|
||||
self.home.get_chat(self.community_name, community=True).click()
|
||||
@@ -114,9 +115,11 @@ class TestCommunityOneDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
try:
|
||||
current_text = self.home.mute_channel_button.unmute_caption_text
|
||||
if current_text not in expected_texts:
|
||||
self.errors.append("Text '%s' is not shown for a channel in muted community" % expected_texts[1])
|
||||
self.errors.append(self.home,
|
||||
"Text '%s' is not shown for a channel in muted community" % expected_texts[1])
|
||||
except NoSuchElementException:
|
||||
self.errors.append("Caption with text 'Muted until...' is not shown for a channel in muted community")
|
||||
self.errors.append(self.home,
|
||||
"Caption with text 'Muted until...' is not shown for a channel in muted community")
|
||||
|
||||
self.home.just_fyi("Unmute channel and check that the community is also unmuted")
|
||||
self.home.mute_channel_button.click()
|
||||
@@ -124,7 +127,7 @@ class TestCommunityOneDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
self.home.communities_tab.click()
|
||||
self.home.get_chat(self.community_name, community=True).long_press_element()
|
||||
if not self.home.element_by_text("Mute community").is_element_displayed():
|
||||
self.errors.append("Community is not unmuted when channel is unmuted")
|
||||
self.errors.append(self.home, "Community is not unmuted when channel is unmuted")
|
||||
self.home.click_system_back_button()
|
||||
|
||||
self.home.just_fyi("Mute channel and check that community is not muted")
|
||||
@@ -140,16 +143,18 @@ class TestCommunityOneDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
try:
|
||||
current_text = self.home.mute_channel_button.unmute_caption_text
|
||||
if current_text not in expected_texts:
|
||||
self.errors.append("Text '%s' is not shown for a muted community channel" % expected_texts[1])
|
||||
self.errors.append(self.home,
|
||||
"Text '%s' is not shown for a muted community channel" % expected_texts[1])
|
||||
except NoSuchElementException:
|
||||
self.errors.append("Caption with text '%s' is not shown for a muted community channel" % expected_texts[1])
|
||||
self.errors.append(self.home,
|
||||
"Caption with text '%s' is not shown for a muted community channel" % expected_texts[1])
|
||||
self.home.click_system_back_button()
|
||||
self.home.navigate_back_to_home_view()
|
||||
self.home.communities_tab.click()
|
||||
self.home.get_chat(self.community_name, community=True).long_press_element()
|
||||
if self.home.element_by_text_part("Muted until").is_element_displayed() or \
|
||||
self.home.mute_community_button.text != transl["mute-community"]:
|
||||
self.errors.append("Community is muted when channel is muted")
|
||||
self.errors.append(self.home, "Community is muted when channel is muted")
|
||||
self.home.click_system_back_button()
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
@@ -172,7 +177,7 @@ class TestCommunityOneDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
# "Incorrect contacts number restored: %s instead of %s" % (contacts_number, len(waku_user.contacts)))
|
||||
for contact in waku_user.contacts:
|
||||
if not self.home.element_by_text(contact).is_element_displayed(30):
|
||||
self.errors.append('%s was not restored as a contact from waku backup!' % contact)
|
||||
self.errors.append(self.home, '%s was not restored as a contact from waku backup!' % contact)
|
||||
# Disabled for simple check as sometimes from waku-backup users restored with 3-random names
|
||||
# self.home.click_system_back_button_until_element_is_shown()
|
||||
# contact_row = self.home.contact_details_row(index=i + 1)
|
||||
@@ -201,7 +206,7 @@ class TestCommunityOneDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
self.home.communities_tab.click()
|
||||
for key in ['admin_open', 'member_open', 'admin_closed', 'member_closed']:
|
||||
if not self.home.element_by_text(waku_user.communities[key]).is_element_displayed(30):
|
||||
self.errors.append("%s was not restored from waku-backup!!" % key)
|
||||
self.errors.append(self.home, "%s was not restored from waku-backup!!" % key)
|
||||
# TODO: there is a bug when pending community sometimes restored as joined; needs investigation
|
||||
# self.home.opened_communities_tab.click()
|
||||
# if not self.home.element_by_text(waku_user.communities['member_pending']).is_element_displayed(30):
|
||||
@@ -222,7 +227,7 @@ class TestCommunityOneDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
self.home.navigate_back_to_home_view()
|
||||
self.home.communities_tab.click()
|
||||
if self.home.element_by_text(waku_user.communities['admin_open']).is_element_displayed(30):
|
||||
self.errors.append("Community of previous user is shown!")
|
||||
self.errors.append(self.home, "Community of previous user is shown!")
|
||||
|
||||
self.home.just_fyi("Check that can remove user from logged out state")
|
||||
self.home.reopen_app(sign_in=False)
|
||||
@@ -230,13 +235,13 @@ class TestCommunityOneDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
user_card.open_user_options()
|
||||
self.sign_in.remove_profile_button.click()
|
||||
if not self.sign_in.element_by_translation_id("remove-profile-confirm-message").is_element_displayed(30):
|
||||
self.errors.append("Warning is not shown on removing profile!")
|
||||
self.errors.append(self.home, "Warning is not shown on removing profile!")
|
||||
self.sign_in.element_by_translation_id("remove").click()
|
||||
|
||||
self.home.just_fyi("Check that removed user is not shown in the list anymore")
|
||||
self.home.reopen_app(sign_in=False)
|
||||
if self.sign_in.element_by_text(recover_user_name).is_element_displayed():
|
||||
self.errors.append("Removed user is re-appeared after relogin!")
|
||||
self.errors.append(self.home, "Removed user is re-appeared after relogin!")
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@@ -279,21 +284,23 @@ class TestCommunityOneDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
except TimeoutException:
|
||||
missing_tags.append(text)
|
||||
if missing_tags:
|
||||
self.errors.append("Community '%s' is missing tag(s) %s." % (community_name, ','.join(tags)))
|
||||
self.errors.append(self.home,
|
||||
"Community '%s' is missing tag(s) %s." % (community_name, ','.join(tags)))
|
||||
# if community_name == 'Status':
|
||||
self.home.just_fyi("Check Status community screen")
|
||||
card.click()
|
||||
if self.community_view.join_button.is_element_differs_from_template(
|
||||
'status_community_join_button.png'):
|
||||
self.errors.append("Status community Join button is different from expected template.")
|
||||
self.errors.append(self.home, "Status community Join button is different from expected template.")
|
||||
if self.community_view.community_logo.is_element_differs_from_template('status_community_logo.png'):
|
||||
self.errors.append("Status community logo is different from expected template.")
|
||||
self.errors.append(self.home, "Status community logo is different from expected template.")
|
||||
|
||||
# self.community_view.close_community_view_button.click()
|
||||
# self.home.swipe_up()
|
||||
|
||||
except TimeoutException:
|
||||
self.errors.append("Community '%s' is not in the Discover Communities list." % community_name)
|
||||
self.errors.append(self.home,
|
||||
"Community '%s' is not in the Discover Communities list." % community_name)
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
# Note: this test should always be the LAST ONE in the group because it turns on mainnet in the app!
|
||||
@@ -350,7 +357,7 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
timestamp = self.channel_1.chat_element_by_text(message).timestamp
|
||||
if sent_time_variants and timestamp:
|
||||
if timestamp not in sent_time_variants:
|
||||
self.errors.append("Timestamp is not shown, expected: '%s', in fact: '%s'" %
|
||||
self.errors.append(self.channel_1, "Timestamp is not shown, expected: '%s', in fact: '%s'" %
|
||||
(", ".join(sent_time_variants), timestamp))
|
||||
self.channel_1.verify_message_is_under_today_text(message, self.errors)
|
||||
self.channel_2.send_message("one more message")
|
||||
@@ -358,7 +365,8 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
self.channel_1.send_message(new_message)
|
||||
self.channel_2.verify_message_is_under_today_text(new_message, self.errors, 60)
|
||||
if self.channel_2.chat_element_by_text(new_message).username.text != self.username_1:
|
||||
self.errors.append("Default username '%s' is not shown next to the received message" % self.username_1)
|
||||
self.errors.append(self.channel_2,
|
||||
"Default username '%s' is not shown next to the received message" % self.username_1)
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.smoke
|
||||
@@ -370,13 +378,13 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
self.channel_1.edit_message_in_chat(message_before_edit, message_after_edit)
|
||||
for channel in (self.channel_1, self.channel_2):
|
||||
if not channel.element_by_text_part(message_after_edit).is_element_displayed(60):
|
||||
self.errors.append('Message is not edited')
|
||||
self.errors.append(channel, 'Message is not edited')
|
||||
message_text_after_edit = message_after_edit + ' (Edited)'
|
||||
self.channel_2.set_reaction(message_text_after_edit)
|
||||
try:
|
||||
self.channel_1.chat_element_by_text(message_text_after_edit).emojis_below_message().wait_for_element_text(1)
|
||||
except (Failed, NoSuchElementException):
|
||||
self.errors.append("Message reaction is not shown for the sender")
|
||||
self.errors.append(self.channel_1, "Message reaction is not shown for the sender")
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(702839)
|
||||
@@ -389,9 +397,9 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
self.channel_2.delete_message_in_chat(message_to_delete_everyone)
|
||||
for channel in (self.channel_1, self.channel_2):
|
||||
if not channel.chat_element_by_text(message_to_delete_everyone).is_element_disappeared(30):
|
||||
self.errors.append("Deleted message is shown in channel")
|
||||
self.errors.append(channel, "Deleted message is shown in channel")
|
||||
if not self.channel_2.element_by_translation_id('message-deleted-for-everyone').is_element_displayed(30):
|
||||
self.errors.append("System message about deletion for everyone is not displayed")
|
||||
self.errors.append(self.channel_2, "System message about deletion for everyone is not displayed")
|
||||
|
||||
self.home_2.just_fyi(
|
||||
'Deleting message for me. Checking that message is deleted only for the author of the message')
|
||||
@@ -399,11 +407,11 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
self.channel_1.chat_element_by_text(message_to_delete_for_me).wait_for_element(120)
|
||||
self.channel_2.delete_message_in_chat(message_to_delete_for_me, everyone=False)
|
||||
if not self.channel_2.chat_element_by_text(message_to_delete_for_me).is_element_disappeared(30):
|
||||
self.errors.append("Deleted for me message is shown in channel for the author of message")
|
||||
self.errors.append(self.channel_2, "Deleted for me message is shown in channel for the author of message")
|
||||
if not self.channel_2.element_by_translation_id('message-deleted-for-you').is_element_displayed(30):
|
||||
self.errors.append("System message about deletion for you is not displayed")
|
||||
self.errors.append(self.channel_2, "System message about deletion for you is not displayed")
|
||||
if not self.channel_1.chat_element_by_text(message_to_delete_for_me).is_element_displayed(30):
|
||||
self.errors.append("Deleted for me message is deleted all channel members")
|
||||
self.errors.append(self.channel_1, "Deleted for me message is deleted all channel members")
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(703194)
|
||||
@@ -423,22 +431,22 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
image = chat_element.image_container_in_message
|
||||
if (image.is_element_differs_from_template("images_gallery.png", 5) and
|
||||
image.is_element_differs_from_template("images_gallery_inverted.png", 5)):
|
||||
self.errors.append("Gallery message does not match the template!")
|
||||
self.errors.append(self.channel_2, "Gallery message does not match the template!")
|
||||
except TimeoutException:
|
||||
self.errors.append("Gallery message was not received")
|
||||
self.errors.append(self.channel_2, "Gallery message was not received")
|
||||
received = False
|
||||
|
||||
if received:
|
||||
self.channel_2.just_fyi("Checking an ability to save and share an image from gallery")
|
||||
chat_element.image_container_in_message.image_by_index(1).click()
|
||||
if not self.channel_2.share_image_icon_button.is_element_displayed():
|
||||
self.errors.append("Can't share an image from gallery.")
|
||||
self.errors.append(self.channel_2, "Can't share an image from gallery.")
|
||||
if self.channel_2.view_image_options_button.is_element_displayed():
|
||||
self.channel_2.view_image_options_button.click()
|
||||
if not self.channel_2.save_image_icon_button.is_element_displayed():
|
||||
self.errors.append("Can't save an image from gallery.")
|
||||
self.errors.append(self.channel_2, "Can't save an image from gallery.")
|
||||
else:
|
||||
self.errors.append("Image options button is not shown for an image from gallery.")
|
||||
self.errors.append(self.channel_2, "Image options button is not shown for an image from gallery.")
|
||||
|
||||
self.channel_2.navigate_back_to_chat_view()
|
||||
|
||||
@@ -450,7 +458,7 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
chat_element_1 = self.channel_1.chat_element_by_text(message_text)
|
||||
if not chat_element_1.is_element_displayed(
|
||||
sec=60) or chat_element_1.replied_message_text != image_description:
|
||||
self.errors.append('Reply message was not received by the sender')
|
||||
self.errors.append(self.channel_1, 'Reply message was not received by the sender')
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(702859)
|
||||
@@ -465,7 +473,7 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
self.channel_2.chat_element_by_text(image_description).wait_for_visibility_of_element(10)
|
||||
if not self.channel_2.chat_element_by_text(
|
||||
image_description).image_in_message.is_element_image_similar_to_template('image_1_chat_view.png'):
|
||||
self.errors.append("Not expected image is shown to the receiver")
|
||||
self.errors.append(self.channel_2, "Not expected image is shown to the receiver")
|
||||
|
||||
if not self.channel_1.chat_element_by_text(image_description).is_element_displayed(60):
|
||||
self.channel_1.hide_keyboard_if_shown()
|
||||
@@ -477,11 +485,11 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
if toast_element.is_element_displayed():
|
||||
toast_element_text = toast_element.text
|
||||
if toast_element_text != self.channel_1.get_translation_by_key("photo-saved"):
|
||||
self.errors.append(
|
||||
"Shown message '%s' doesn't match expected '%s' after saving an image." % (
|
||||
toast_element_text, self.channel_1.get_translation_by_key("photo-saved")))
|
||||
self.errors.append(self.channel_1,
|
||||
"Shown message '%s' doesn't match expected '%s' after saving an image." % (
|
||||
toast_element_text, self.channel_1.get_translation_by_key("photo-saved")))
|
||||
else:
|
||||
self.errors.append("Message about saving a photo is not shown.")
|
||||
self.errors.append(self.channel_1, "Message about saving a photo is not shown.")
|
||||
self.channel_1.navigate_back_to_chat_view()
|
||||
|
||||
self.channel_1.just_fyi("Check that image is saved in gallery")
|
||||
@@ -489,7 +497,7 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
self.channel_1.allow_all_button.click_if_shown()
|
||||
if not self.channel_1.get_image_by_index(0).is_element_image_similar_to_template(
|
||||
"image_1_gallery_view.png"):
|
||||
self.errors.append('Saved image is not shown in Recent')
|
||||
self.errors.append(self.channel_1, 'Saved image is not shown in Recent')
|
||||
self.channel_1.click_system_back_button()
|
||||
|
||||
self.home_2.just_fyi('Check share option on opened image')
|
||||
@@ -499,7 +507,7 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
try:
|
||||
self.channel_2.wait_for_current_package_to_be('com.google.android.apps.docs')
|
||||
except TimeoutException:
|
||||
self.errors.append("Can't share image")
|
||||
self.errors.append(self.channel_2, "Can't share image")
|
||||
self.channel_2.navigate_back_to_chat_view()
|
||||
|
||||
self.channel_2.just_fyi("Can reply to images")
|
||||
@@ -511,20 +519,20 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
self.channel_2.send_message_button.click()
|
||||
chat_element_1 = self.channel_1.chat_element_by_text(message_text)
|
||||
if not chat_element_1.is_element_displayed(sec=60) or chat_element_1.replied_message_text != image_description:
|
||||
self.errors.append('Reply message was not received by the sender')
|
||||
self.errors.append(self.channel_1, 'Reply message was not received by the sender')
|
||||
self.channel_2.just_fyi("Set a reaction for the image message")
|
||||
self.channel_2.set_reaction(message=image_description)
|
||||
try:
|
||||
self.channel_1.chat_element_by_text(image_description).emojis_below_message().wait_for_element_text(1)
|
||||
except (Failed, NoSuchElementException):
|
||||
self.errors.append("Image message reaction is not shown for the sender")
|
||||
self.errors.append(self.channel_1, "Image message reaction is not shown for the sender")
|
||||
self.channel_1.just_fyi("Set a reaction for the message reply")
|
||||
self.channel_2.set_reaction(message=image_description, emoji="love")
|
||||
try:
|
||||
self.channel_2.chat_element_by_text(message_text).emojis_below_message(
|
||||
emoji="love").wait_for_element_text(1)
|
||||
except (Failed, NoSuchElementException):
|
||||
self.errors.append("Reply message reaction is not shown for the reply sender")
|
||||
self.errors.append(self.channel_2, "Reply message reaction is not shown for the reply sender")
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@@ -537,13 +545,14 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
self.channel_1.send_message(emoji_message)
|
||||
for channel in self.channel_1, self.channel_2:
|
||||
if not channel.chat_element_by_text(emoji_unicode).is_element_displayed(30):
|
||||
self.errors.append('Message with emoji was not sent or received in community channel')
|
||||
self.errors.append(channel, 'Message with emoji was not sent or received in community channel')
|
||||
|
||||
self.channel_1.just_fyi("Can copy and paste emojis")
|
||||
self.channel_1.copy_message_text(emoji_unicode)
|
||||
actual_copied_text = self.channel_1.driver.get_clipboard_text()
|
||||
if actual_copied_text != emoji_unicode:
|
||||
self.errors.append('Emoji message was not copied, text in clipboard is %s' % actual_copied_text)
|
||||
self.errors.append(self.channel_1,
|
||||
'Emoji message was not copied, text in clipboard is %s' % actual_copied_text)
|
||||
|
||||
self.channel_1.just_fyi("Can reply to emojis")
|
||||
if not self.channel_2.chat_message_input.is_element_displayed():
|
||||
@@ -557,7 +566,7 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
chat_element_1 = self.channel_1.chat_element_by_text(message_text)
|
||||
chat_element_1.wait_for_element(60)
|
||||
if chat_element_1.replied_message_text != emoji_unicode:
|
||||
self.errors.append('Reply message is not reply to original message!')
|
||||
self.errors.append(self.channel_1, 'Reply message is not reply to original message!')
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(702844)
|
||||
@@ -613,27 +622,30 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
try:
|
||||
self.channel_2.url_preview_composer.wait_for_element(20)
|
||||
except TimeoutException:
|
||||
self.errors.append("No preview is loaded for url %s" % url)
|
||||
self.errors.append(self.channel_1, "No preview is loaded for url %s" % url)
|
||||
self.channel_2.send_message_button.click()
|
||||
continue
|
||||
shown_title = self.channel_2.url_preview_composer_text.text
|
||||
if shown_title != data['title']:
|
||||
self.errors.append("Preview text is not expected, it is '%s'" % shown_title)
|
||||
self.errors.append(self.channel_2, "Preview text is not expected, it is '%s'" % shown_title)
|
||||
self.channel_2.send_message_button.click()
|
||||
message = self.channel_1.get_preview_message_by_text(url)
|
||||
message.wait_for_element(60)
|
||||
if not message.preview_image:
|
||||
self.errors.append("No preview image is shown for %s" % url)
|
||||
self.errors.append(self.channel_1, "No preview image is shown for %s" % url)
|
||||
shown_title = message.preview_title.text
|
||||
if shown_title != data['title']:
|
||||
self.errors.append("Title is not equal expected for '%s', actual is '%s'" % (url, shown_title))
|
||||
self.errors.append(self.channel_1,
|
||||
"Title is not equal expected for '%s', actual is '%s'" % (url, shown_title))
|
||||
shown_description = message.preview_subtitle.text
|
||||
if shown_description != data['description']:
|
||||
self.errors.append(
|
||||
"Description is not equal expected for '%s', actual is '%s'" % (url, shown_description))
|
||||
self.errors.append(self.channel_1,
|
||||
"Description is not equal expected for '%s', actual is '%s'" % (
|
||||
url, shown_description))
|
||||
shown_link = message.preview_link.text
|
||||
if shown_link != data['link']:
|
||||
self.errors.append("Link is not equal expected for '%s', actual is '%s'" % (url, shown_link))
|
||||
self.errors.append(self.channel_1,
|
||||
"Link is not equal expected for '%s', actual is '%s'" % (url, shown_link))
|
||||
|
||||
self.channel_1.just_fyi("Set reaction and check it")
|
||||
message_with_reaction = list(preview_urls.values())[-1]['url']
|
||||
@@ -645,7 +657,7 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
self.channel_2.chat_element_by_text(message_with_reaction).emojis_below_message(
|
||||
emoji="laugh").wait_for_element_text(1)
|
||||
except (Failed, NoSuchElementException):
|
||||
self.errors.append("Link message reaction is not shown for the sender")
|
||||
self.errors.append(self.channel_2, "Link message reaction is not shown for the sender")
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@@ -662,14 +674,14 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
self.home_1.just_fyi('Check new messages badge is shown for community')
|
||||
community_element_1 = self.home_1.get_chat(self.community_name, community=True)
|
||||
if not community_element_1.new_messages_grey_dot.is_element_displayed(sec=30):
|
||||
self.errors.append('New message community badge is not shown')
|
||||
self.errors.append(self.home_1, 'New message community badge is not shown')
|
||||
|
||||
community_1 = community_element_1.click()
|
||||
channel_1_element = community_1.get_channel(self.channel_name)
|
||||
|
||||
self.home_1.just_fyi('Check new messages badge is shown for channel')
|
||||
if not channel_1_element.new_messages_grey_dot.is_element_displayed():
|
||||
self.errors.append('New messages channel badge is not shown on channel')
|
||||
self.errors.append(self.channel_1, 'New messages channel badge is not shown on channel')
|
||||
channel_1_element.click()
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@@ -696,7 +708,7 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
|
||||
self.chat_1.just_fyi('Check that messages from blocked user are hidden in public chat and close app')
|
||||
if not self.chat_1.chat_element_by_text(message_to_disappear).is_element_disappeared(30):
|
||||
self.errors.append("Messages from blocked user is not cleared in public chat ")
|
||||
self.errors.append(self.chat_1, "Messages from blocked user is not cleared in public chat ")
|
||||
self.chat_1.navigate_back_to_home_view()
|
||||
# ToDo: enable when https://github.com/status-im/status-mobile/issues/19334 is fixed
|
||||
# self.home_1.chats_tab.click()
|
||||
@@ -715,8 +727,8 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
self.home_1.get_chat(self.channel_name, community_channel=True).click()
|
||||
for message in message_to_disappear, message_blocked:
|
||||
if self.chat_1.chat_element_by_text(message).is_element_displayed(30):
|
||||
self.errors.append(
|
||||
"'%s' from blocked user is fetched from offline in community channel" % message)
|
||||
self.errors.append(self.chat_1,
|
||||
"'%s' from blocked user is fetched from offline in community channel" % message)
|
||||
|
||||
self.chat_1.just_fyi('Unblock user and check that can see further messages')
|
||||
# TODO: still no blocked users in new UI
|
||||
@@ -736,7 +748,8 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
self.home_1.get_chat(self.channel_name, community_channel=True).click()
|
||||
self.chat_1.hide_keyboard_if_shown()
|
||||
if not self.chat_1.chat_element_by_text(message_unblocked).is_element_displayed(120):
|
||||
self.errors.append("%s was not received in public chat after user unblock!" % message_unblocked)
|
||||
self.errors.append(self.chat_1,
|
||||
"%s was not received in public chat after user unblock!" % message_unblocked)
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
self.home_1.just_fyi("Add blocked user to contacts again after removing(removed automatically when blocked)")
|
||||
@@ -756,7 +769,7 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
unblocked = True
|
||||
except TimeoutException:
|
||||
unblocked = False
|
||||
self.errors.append("Chat with unblocked user was not enabled after 1 minute")
|
||||
self.errors.append(self.chat_1, "Chat with unblocked user was not enabled after 1 minute")
|
||||
|
||||
if unblocked:
|
||||
self.home_2.just_fyi("Check message in 1-1 chat after unblock")
|
||||
@@ -767,9 +780,9 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
self.chat_2.chat_element_by_text(message_unblocked).wait_for_status_to_be(expected_status='Delivered',
|
||||
timeout=120)
|
||||
if not self.chat_1.chat_element_by_text(message_unblocked).is_element_displayed(30):
|
||||
self.errors.append("Message was not received in 1-1 chat after user unblock!")
|
||||
self.errors.append(self.chat_1, "Message was not received in 1-1 chat after user unblock!")
|
||||
except TimeoutException:
|
||||
self.errors.append('Message was not delivered after back up online.')
|
||||
self.errors.append(self.chat_2, 'Message was not delivered after back up online.')
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@@ -783,22 +796,23 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
self.channel_2.send_message(self.text_message)
|
||||
community_1_element = self.community_1.get_chat(self.community_name, community=True)
|
||||
if not community_1_element.new_messages_grey_dot.is_element_displayed(90):
|
||||
self.errors.append('New messages counter is not shown in home > Community element')
|
||||
self.errors.append(self.community_1, 'New messages counter is not shown in home > Community element')
|
||||
community_1_element.click()
|
||||
channel_1_element = self.community_1.get_chat(self.channel_name, community_channel=True)
|
||||
if not channel_1_element.new_messages_grey_dot.is_element_displayed():
|
||||
self.errors.append("New messages counter is not shown in community channel element")
|
||||
self.errors.append(self.community_1, "New messages counter is not shown in community channel element")
|
||||
self.community_1.click_system_back_button()
|
||||
mark_as_read_button = self.community_1.mark_all_messages_as_read_button
|
||||
self.home_1.community_floating_screen.wait_for_invisibility_of_element()
|
||||
community_1_element.long_press_until_element_is_shown(mark_as_read_button)
|
||||
mark_as_read_button.click()
|
||||
if community_1_element.new_messages_grey_dot.is_element_displayed():
|
||||
self.errors.append(
|
||||
'Unread messages badge is shown in community element while there are no unread messages')
|
||||
self.errors.append(self.community_1,
|
||||
'Unread messages badge is shown in community element while there are no unread messages')
|
||||
community_1_element.click()
|
||||
if channel_1_element.new_messages_grey_dot.is_element_displayed():
|
||||
self.errors.append(
|
||||
self.community_1,
|
||||
"New messages badge is shown in community channel element while there are no unread messages")
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@@ -827,9 +841,10 @@ class TestCommunityMultipleDeviceMerged(MultipleSharedDeviceTestCase):
|
||||
|
||||
self.channel_1.just_fyi("Receiver is checking if messages were updated and deleted")
|
||||
if not self.channel_1.chat_element_by_text(message_after_edit).is_element_displayed(30):
|
||||
self.errors.append("Updated message '%s' is not delivered to the receiver" % message_after_edit)
|
||||
self.errors.append(self.channel_1,
|
||||
"Updated message '%s' is not delivered to the receiver" % message_after_edit)
|
||||
if not self.channel_1.chat_element_by_text(message_to_delete).is_element_disappeared():
|
||||
self.errors.append("Message '%s' was not deleted for the receiver" % message_to_delete)
|
||||
self.errors.append(self.channel_1, "Message '%s' was not deleted for the receiver" % message_to_delete)
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
|
||||
@@ -890,12 +905,13 @@ class TestCommunityMultipleDeviceMergedTwo(MultipleSharedDeviceTestCase):
|
||||
message_received = True
|
||||
if not self.channel_1.chat_element_by_text(self.username_1).is_element_displayed():
|
||||
if self.channel_1.chat_message_input.is_element_displayed():
|
||||
self.errors.append("Message with the mention is not shown in the chat for the admin")
|
||||
self.errors.append(self.channel_1,
|
||||
"Message with the mention is not shown in the chat for the admin")
|
||||
else:
|
||||
self.errors.append(
|
||||
"Channel did not open by clicking on a notification with the mention for admin")
|
||||
self.errors.append(self.channel_1,
|
||||
"Channel did not open by clicking on a notification with the mention for admin")
|
||||
else:
|
||||
self.errors.append("Push notification with the mention was not received by admin")
|
||||
self.errors.append(self.channel_1, "Push notification with the mention was not received by admin")
|
||||
|
||||
if not self.channel_1.chat_message_input.is_element_displayed():
|
||||
self.channel_1.navigate_back_to_home_view()
|
||||
@@ -925,20 +941,20 @@ class TestCommunityMultipleDeviceMergedTwo(MultipleSharedDeviceTestCase):
|
||||
self.channel_2.send_message_button.click()
|
||||
edit_done = True
|
||||
if chat_element.message_body_with_mention.text != expected_message:
|
||||
self.errors.append("Edited message is not shown correctly for the sender")
|
||||
self.errors.append(self.channel_2, "Edited message is not shown correctly for the sender")
|
||||
except NoSuchElementException:
|
||||
self.errors.append("Can not edit a message with a mention")
|
||||
self.errors.append(self.channel_2, "Can not edit a message with a mention")
|
||||
if edit_done:
|
||||
element = self.channel_1.chat_element_by_text(self.username_1).message_body_with_mention
|
||||
if not element.is_element_displayed(10) or element.text != expected_message:
|
||||
self.errors.append("Edited message is not shown correctly for the (receiver) admin")
|
||||
self.errors.append(self.channel_1, "Edited message is not shown correctly for the (receiver) admin")
|
||||
|
||||
self.device_2.just_fyi("Sender checks the reaction for a message with a mention")
|
||||
try:
|
||||
self.channel_2.chat_element_by_text(self.username_1).emojis_below_message(
|
||||
emoji="sad").wait_for_element_text(1)
|
||||
except (Failed, NoSuchElementException):
|
||||
self.errors.append("Message reaction is not shown for the sender")
|
||||
self.errors.append(self.channel_2, "Message reaction is not shown for the sender")
|
||||
|
||||
self.home_2.navigate_back_to_home_view()
|
||||
if not self.channel_1.chat_message_input.is_element_displayed():
|
||||
@@ -957,12 +973,15 @@ class TestCommunityMultipleDeviceMergedTwo(MultipleSharedDeviceTestCase):
|
||||
push_notification_element.click()
|
||||
if not self.channel_2.chat_element_by_text(self.username_2).is_element_displayed():
|
||||
if self.channel_2.chat_message_input.is_element_displayed():
|
||||
self.errors.append("Message with the mention is not shown in the chat for the invited member")
|
||||
self.errors.append(self.channel_2,
|
||||
"Message with the mention is not shown in the chat for the invited member")
|
||||
else:
|
||||
self.errors.append(
|
||||
self.channel_2,
|
||||
"Channel did not open by clicking on a notification with the mention for the invited member")
|
||||
else:
|
||||
self.errors.append("Push notification with the mention was not received by the invited member")
|
||||
self.errors.append(self.channel_2,
|
||||
"Push notification with the mention was not received by the invited member")
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(702809)
|
||||
@@ -989,11 +1008,13 @@ class TestCommunityMultipleDeviceMergedTwo(MultipleSharedDeviceTestCase):
|
||||
self.channel_2.send_message(message_to_send)
|
||||
if not self.channel_2.chat_element_by_text(message).is_element_displayed():
|
||||
self.errors.append(
|
||||
'%s is not displayed with markdown in community channel for the sender (device 2) \n' % message)
|
||||
self.channel_2,
|
||||
'%s is not displayed with markdown in community channel for the sender \n' % message)
|
||||
|
||||
if not self.channel_1.chat_element_by_text(message).is_element_displayed():
|
||||
self.errors.append(
|
||||
'%s is not displayed with markdown in community channel for the recipient (device 1) \n' % message)
|
||||
self.channel_1,
|
||||
'%s is not displayed with markdown in community channel for the recipient \n' % message)
|
||||
|
||||
for home in self.homes:
|
||||
home.navigate_back_to_home_view()
|
||||
@@ -1009,10 +1030,11 @@ class TestCommunityMultipleDeviceMergedTwo(MultipleSharedDeviceTestCase):
|
||||
self.chat_1.send_message(message_to_send)
|
||||
if not self.chat_1.chat_element_by_text(message).is_element_displayed(30):
|
||||
self.errors.append(
|
||||
'%s is not displayed with markdown in 1-1 chat for the sender (device 1) \n' % message)
|
||||
self.chat_1, '%s is not displayed with markdown in 1-1 chat for the sender (device 1) \n' % message)
|
||||
|
||||
if not self.chat_2.chat_element_by_text(message).is_element_displayed(30):
|
||||
self.errors.append(
|
||||
self.chat_2,
|
||||
'%s is not displayed with markdown in 1-1 chat for the recipient (device 2) \n' % message)
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
@@ -1027,7 +1049,7 @@ class TestCommunityMultipleDeviceMergedTwo(MultipleSharedDeviceTestCase):
|
||||
community_to_leave.leave_community_button.click()
|
||||
community_to_leave.leave_community_button.click()
|
||||
if not community.is_element_disappeared():
|
||||
self.errors.append('Community is still shown in the list after leave')
|
||||
self.errors.append(self.home_2, 'Community is still shown in the list after leave')
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.xfail(reason="Can't navigate to a community channel before joining the community, "
|
||||
@@ -1058,12 +1080,13 @@ class TestCommunityMultipleDeviceMergedTwo(MultipleSharedDeviceTestCase):
|
||||
if not self.community_2.get_channel(chan_name).is_element_displayed():
|
||||
not_shown.append(chan_name)
|
||||
if not_shown:
|
||||
self.errors.append("Not all channels are shown in community before joining: %s" % not_shown)
|
||||
self.errors.append(self.community_2,
|
||||
"Not all channels are shown in community before joining: %s" % not_shown)
|
||||
chan = self.community_2.get_channel("general")
|
||||
if chan.is_element_displayed():
|
||||
chan.find_element().click()
|
||||
if not self.channel_2.chat_element_by_text(control_message_general_chat).is_element_displayed(20):
|
||||
self.errors.append("Message in community channel is not visible for user before join")
|
||||
self.errors.append(self.channel_2, "Message in community channel is not visible for user before join")
|
||||
else:
|
||||
not_shown.append("general")
|
||||
|
||||
@@ -1078,7 +1101,7 @@ class TestCommunityMultipleDeviceMergedTwo(MultipleSharedDeviceTestCase):
|
||||
try:
|
||||
self.home_1.notifications_unread_badge.wait_for_visibility_of_element(120)
|
||||
except TimeoutException:
|
||||
self.errors.append("Unread indicator is not shown in notifications on membership request")
|
||||
self.errors.append(self.home_1, "Unread indicator is not shown in notifications on membership request")
|
||||
self.home_1.open_activity_center_button.click()
|
||||
reply_element = self.home_1.get_element_from_activity_center_view(self.username_2)
|
||||
reply_element.title.swipe_right_on_element(width_percentage=2.5)
|
||||
@@ -1104,12 +1127,12 @@ class TestCommunityMultipleDeviceMergedTwo(MultipleSharedDeviceTestCase):
|
||||
self.home_2.get_to_community_channel_from_home(community_name, dogs_channel)
|
||||
self.channel_2.chat_element_by_text(message_with_hashtag).click_on_link_inside_message_body()
|
||||
if not self.channel_2.chat_element_by_text(cats_message).is_element_displayed(30):
|
||||
self.errors.append("Receiver was not navigated to the cats channel")
|
||||
self.errors.append(self.channel_2, "Receiver was not navigated to the cats channel")
|
||||
|
||||
self.home_1.just_fyi("Device 1 clicks on the message with hashtag in the community channel")
|
||||
self.channel_1.chat_element_by_text(message_with_hashtag).click_on_link_inside_message_body()
|
||||
if not self.channel_1.chat_element_by_text(cats_message).is_element_displayed(30):
|
||||
self.errors.append("Sender was not navigated to the cats channel")
|
||||
self.errors.append(self.channel_1, "Sender was not navigated to the cats channel")
|
||||
|
||||
for home in self.homes:
|
||||
home.navigate_back_to_home_view()
|
||||
@@ -1123,12 +1146,12 @@ class TestCommunityMultipleDeviceMergedTwo(MultipleSharedDeviceTestCase):
|
||||
self.home_1.get_chat(self.username_2).click()
|
||||
self.chat_1.chat_element_by_text(message_with_hashtag).click_on_link_inside_message_body()
|
||||
if self.chat_1.chat_element_by_text(control_message_1_1_chat).is_element_disappeared():
|
||||
self.errors.append("Receiver was navigated out of 1-1 chat")
|
||||
self.errors.append(self.chat_1, "Receiver was navigated out of 1-1 chat")
|
||||
|
||||
self.home_2.just_fyi("Device 2 clicks on the message with hashtag in 1-1 chat")
|
||||
self.chat_2.chat_element_by_text(message_with_hashtag).click_on_link_inside_message_body()
|
||||
if self.chat_2.chat_element_by_text(control_message_1_1_chat).is_element_disappeared():
|
||||
self.errors.append("Sender was navigated out of 1-1 chat")
|
||||
self.errors.append(self.chat_2, "Sender was navigated out of 1-1 chat")
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@@ -1169,21 +1192,23 @@ class TestCommunityMultipleDeviceMergedTwo(MultipleSharedDeviceTestCase):
|
||||
if self.community_2.toast_content_element.is_element_displayed(10):
|
||||
cur_text = self.community_2.toast_content_element.text
|
||||
if cur_text != exp_text:
|
||||
self.errors.append(
|
||||
"Text \"%s\" in shown toast element doesn't match expected \"%s\"" % (cur_text, exp_text))
|
||||
self.errors.append(self.community_2,
|
||||
"Text \"%s\" in shown toast element doesn't match expected \"%s\"" % (
|
||||
cur_text, exp_text))
|
||||
else:
|
||||
self.errors.append("Toast element with the text \"%s\" doesn't appear" % exp_text)
|
||||
self.errors.append(self.community_2, "Toast element with the text \"%s\" doesn't appear" % exp_text)
|
||||
if not self.community_2.community_status_pending.is_element_displayed():
|
||||
self.errors.append("Pending status is not displayed")
|
||||
self.errors.append(self.community_2, "Pending status is not displayed")
|
||||
general_channel = self.community_2.get_channel("general")
|
||||
if general_channel.is_element_displayed():
|
||||
general_channel.find_element().click()
|
||||
if not self.channel_2.chat_element_by_text(control_message_general_chat).is_element_displayed(30):
|
||||
self.errors.append(
|
||||
self.community_2,
|
||||
"Message in community channel is not visible for user before join, it was indicated as " \
|
||||
"%s sent for the sender before he went offline" % ("" if message_sent else "not"))
|
||||
else:
|
||||
self.errors.append("Community channel is not displayed for user before join")
|
||||
self.errors.append(self.community_2, "Community channel is not displayed for user before join")
|
||||
self.community_2.toast_content_element.wait_for_invisibility_of_element(30)
|
||||
self.home_2.navigate_back_to_home_view()
|
||||
self.home_2.communities_tab.click()
|
||||
@@ -1191,7 +1216,7 @@ class TestCommunityMultipleDeviceMergedTwo(MultipleSharedDeviceTestCase):
|
||||
if self.home_2.get_chat(community_name, community=True).is_element_displayed():
|
||||
self.home_2.get_chat(community_name, community=True).click()
|
||||
else:
|
||||
self.errors.append("%s is not listed inside Pending communities tab" % community_name)
|
||||
self.errors.append(self.home_2, "%s is not listed inside Pending communities tab" % community_name)
|
||||
|
||||
self.home_1.just_fyi("Device 1 goes back online")
|
||||
self.home_1.driver.activate_app(app_package)
|
||||
@@ -1202,13 +1227,14 @@ class TestCommunityMultipleDeviceMergedTwo(MultipleSharedDeviceTestCase):
|
||||
if self.community_2.toast_content_element.is_element_displayed(60):
|
||||
cur_text = self.community_2.toast_content_element.text
|
||||
if cur_text != exp_text:
|
||||
self.errors.append(
|
||||
"Text \"%s\" in shown toast element doesn't match expected \"%s\"" % (cur_text, exp_text))
|
||||
self.errors.append(self.community_2,
|
||||
"Text \"%s\" in shown toast element doesn't match expected \"%s\"" % (
|
||||
cur_text, exp_text))
|
||||
# else:
|
||||
# self.errors.append("Toast element with the text \"%s\" doesn't appear" % exp_text)
|
||||
# ToDo: add verification when toast is fixed
|
||||
if not self.community_2.community_status_joined.is_element_displayed():
|
||||
self.errors.append("Joined status is not displayed")
|
||||
self.errors.append(self.community_2, "Joined status is not displayed")
|
||||
self.community_2.close_community_view_button.click_until_absense_of_element(
|
||||
self.community_2.close_community_view_button)
|
||||
self.home_2.joined_communities_tab.click()
|
||||
@@ -1216,6 +1242,6 @@ class TestCommunityMultipleDeviceMergedTwo(MultipleSharedDeviceTestCase):
|
||||
if chat_element.is_element_displayed(30):
|
||||
chat_element.click()
|
||||
else:
|
||||
self.errors.append("%s is not listed inside Joined communities tab" % community_name)
|
||||
self.errors.append(self.home_2, "%s is not listed inside Joined communities tab" % community_name)
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@@ -42,9 +42,9 @@ class TestDeepLinksOneDevice(MultipleSharedDeviceTestCase):
|
||||
if self.channel.profile_send_contact_request_button.is_element_displayed(10):
|
||||
username_text = self.profile_view.contact_name_text.text
|
||||
if not (username_text.endswith(url[-6:]) or username_text == text):
|
||||
self.errors.append("Incorrect username is shown for profile url %s" % url)
|
||||
self.errors.append(self.channel, "Incorrect username is shown for profile url %s" % url)
|
||||
else:
|
||||
self.errors.append("Profile was not opened by the profile url %s" % url)
|
||||
self.errors.append(self.channel, "Profile was not opened by the profile url %s" % url)
|
||||
self.profile_view.close_button.click()
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
@@ -69,7 +69,7 @@ class TestDeepLinksOneDevice(MultipleSharedDeviceTestCase):
|
||||
else:
|
||||
name_is_shown = shown_name_text.endswith(link[-6:])
|
||||
if not self.channel.profile_send_contact_request_button.is_element_displayed(10) or not name_is_shown:
|
||||
self.errors.append("Profile was not opened by the profile deep link %s" % link)
|
||||
self.errors.append(self.channel, "Profile was not opened by the profile deep link %s" % link)
|
||||
self.browser_view.click_system_back_button()
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
@@ -103,11 +103,13 @@ class TestDeepLinksOneDevice(MultipleSharedDeviceTestCase):
|
||||
self.browser_view.open_url(link)
|
||||
if text == snt_community_name:
|
||||
if self.community_view.community_title.text != text:
|
||||
self.errors.append("Community '%s' was not requested to join by the deep link %s" % (text, link))
|
||||
self.errors.append(self.community_view,
|
||||
"Community '%s' was not requested to join by the deep link %s" % (text, link))
|
||||
else:
|
||||
if not self.community_view.join_button.is_element_displayed(
|
||||
10) or self.community_view.community_title.text != text:
|
||||
self.errors.append("Community '%s' was not requested to join by the deep link %s" % (text, link))
|
||||
self.errors.append(self.community_view,
|
||||
"Community '%s' was not requested to join by the deep link %s" % (text, link))
|
||||
if text != closed_community_name: # the last one
|
||||
self.home.navigate_back_to_home_view()
|
||||
self.home.browser_tab.click()
|
||||
@@ -123,7 +125,8 @@ class TestDeepLinksOneDevice(MultipleSharedDeviceTestCase):
|
||||
self.home.open_link_from_google_search_app(profile_url, app_package)
|
||||
if not self.channel.profile_add_to_contacts_button.is_element_displayed(
|
||||
10) or not self.profile_view.default_username_text.text.endswith(profile_url[-6:]):
|
||||
self.errors.append("Profile was not opened by the url %s when user is logged in" % profile_url)
|
||||
self.errors.append(self.profile_view,
|
||||
"Profile was not opened by the url %s when user is logged in" % profile_url)
|
||||
|
||||
self.home.just_fyi("Opening a community URL from google search bar when user is logged out")
|
||||
self.driver.terminate_app(app_package)
|
||||
@@ -131,7 +134,8 @@ class TestDeepLinksOneDevice(MultipleSharedDeviceTestCase):
|
||||
self.home.open_link_from_google_search_app(community_url, app_package)
|
||||
self.sign_in.sign_in(user_name=self.username)
|
||||
if not self.community_view.join_button.is_element_displayed(10):
|
||||
self.errors.append("Closed community was not requested to join by the url %s" % community_url)
|
||||
self.errors.append(self.community_view,
|
||||
"Closed community was not requested to join by the url %s" % community_url)
|
||||
|
||||
# ToDo: enable when https://github.com/status-im/status-mobile/issues/18074 is fixed
|
||||
# self.home.just_fyi("Opening a community channel URL from google search bar with no account created")
|
||||
|
||||
@@ -72,9 +72,11 @@ class TestFallbackMultipleDevice(MultipleSharedDeviceTestCase):
|
||||
if device_element.is_element_displayed():
|
||||
if not device_element.get_pair_button.is_element_displayed():
|
||||
self.errors.append(
|
||||
self.profile_1,
|
||||
"Pair button is absent for the device 2 inside Paired devices list of profile 1 before pairing")
|
||||
else:
|
||||
self.errors.append("Device 2 is not shown in Paired devices list for device 1 before pairing")
|
||||
self.errors.append(self.profile_1,
|
||||
"Device 2 is not shown in Paired devices list for device 1 before pairing")
|
||||
self.profile_1.click_system_back_button(times=3)
|
||||
|
||||
for home in self.home_1, self.home_2:
|
||||
@@ -84,9 +86,10 @@ class TestFallbackMultipleDevice(MultipleSharedDeviceTestCase):
|
||||
self.home_1.just_fyi("Checking pairing request on device 1")
|
||||
a_c_element = self.home_1.get_activity_center_element_by_text(transl['review-pairing-request'])
|
||||
if a_c_element.title.text != transl['new-device-detected']:
|
||||
self.errors.append(
|
||||
"Notification with title '%s' is not shown in the activity center for the device 1" % transl[
|
||||
'new-device-detected'])
|
||||
self.errors.append(self.home_1,
|
||||
"Notification with title '%s' is not shown in the activity center for the device 1" %
|
||||
transl[
|
||||
'new-device-detected'])
|
||||
a_c_element.review_pairing_request_button.click()
|
||||
device_id_1 = self.home_1.get_new_device_installation_id()
|
||||
|
||||
@@ -95,14 +98,15 @@ class TestFallbackMultipleDevice(MultipleSharedDeviceTestCase):
|
||||
self.home_2.just_fyi("Checking sync profile on device 2")
|
||||
a_c_element = self.home_2.get_activity_center_element_by_text(transl['more-details'])
|
||||
if a_c_element.title.text != transl['sync-your-profile']:
|
||||
self.errors.append(
|
||||
"Notification with title '%s' is not shown in the activity center for the device 2" % transl[
|
||||
'sync-your-profile'])
|
||||
self.errors.append(self.home_2,
|
||||
"Notification with title '%s' is not shown in the activity center for the device 2" %
|
||||
transl[
|
||||
'sync-your-profile'])
|
||||
a_c_element.more_details_button.click()
|
||||
device_id_2 = self.home_2.get_new_device_installation_id()
|
||||
|
||||
if device_id_1 != device_id_2:
|
||||
self.errors.append("Device ids don't match on the activity center notifications")
|
||||
self.errors.append(self.home_2, "Device ids don't match on the activity center notifications")
|
||||
|
||||
self.home_1.just_fyi("Confirm pairing request on device 1")
|
||||
self.home_1.element_by_translation_id('pair-and-sync').click()
|
||||
@@ -121,9 +125,11 @@ class TestFallbackMultipleDevice(MultipleSharedDeviceTestCase):
|
||||
if device_element.is_element_displayed():
|
||||
if not device_element.get_unpair_button.is_element_displayed():
|
||||
self.errors.append(
|
||||
self.profile_1,
|
||||
"Unpair button is absent for the device 2 inside Paired devices list of profile 1 after pairing")
|
||||
else:
|
||||
self.errors.append("Device 2 is not shown in Paired devices list for device 1 after pairing")
|
||||
self.errors.append(self.profile_1,
|
||||
"Device 2 is not shown in Paired devices list for device 1 after pairing")
|
||||
|
||||
self.home_2.just_fyi("Device 2: Check that the device 1 is shown paired devices list")
|
||||
self.home_2.profile_button.click()
|
||||
@@ -133,9 +139,11 @@ class TestFallbackMultipleDevice(MultipleSharedDeviceTestCase):
|
||||
if device_element.is_element_displayed():
|
||||
if not device_element.get_unpair_button.is_element_displayed():
|
||||
self.errors.append(
|
||||
self.profile_2,
|
||||
"Unpair button is absent for the device 1 inside Paired devices list of profile 2 after pairing")
|
||||
else:
|
||||
self.errors.append("Device 1 is not shown in Paired devices list for device 2 after pairing")
|
||||
self.errors.append(self.profile_2,
|
||||
"Device 1 is not shown in Paired devices list for device 2 after pairing")
|
||||
|
||||
self.home_3.just_fyi("Device 3: send a message to user 1")
|
||||
self.home_3.chats_tab.click()
|
||||
@@ -153,7 +161,7 @@ class TestFallbackMultipleDevice(MultipleSharedDeviceTestCase):
|
||||
chat_view = chat_element.click()
|
||||
chat_view.chat_element_by_text(message).wait_for_visibility_of_element(60)
|
||||
except TimeoutException:
|
||||
self.errors.append("Message is not received by the user %s" % index)
|
||||
self.errors.append(home_view, "Message is not received by the user %s" % index)
|
||||
|
||||
self.loop.run_until_complete(
|
||||
run_in_parallel(((_check_message, {'home_view': self.home_1, 'index': 1}),
|
||||
@@ -178,11 +186,12 @@ class TestFallbackMultipleDevice(MultipleSharedDeviceTestCase):
|
||||
wallet_1.close_account_button.click_until_presence_of_element(account_element)
|
||||
|
||||
if regular_account_address != expected_addresses[1]:
|
||||
self.errors.append("Newly added regular account address %s doesn't match expected %s" % (
|
||||
self.errors.append(wallet_1, "Newly added regular account address %s doesn't match expected %s" % (
|
||||
regular_account_address, expected_addresses[1]))
|
||||
if regular_account_address not in expected_addresses:
|
||||
self.errors.append("Newly added regular account address %s is not in the list of expected addresses %s" % (
|
||||
regular_account_address, expected_addresses))
|
||||
self.errors.append(wallet_1,
|
||||
"Newly added regular account address %s is not in the list of expected addresses %s" % (
|
||||
regular_account_address, expected_addresses))
|
||||
|
||||
wallet_1.just_fyi("Device 1: add a new key pair account by importing recovery phrase")
|
||||
account_element.swipe_left_on_element()
|
||||
@@ -210,7 +219,7 @@ class TestFallbackMultipleDevice(MultipleSharedDeviceTestCase):
|
||||
]
|
||||
for text in expected_texts_regular:
|
||||
if not wallet_1.default_key_pair_container.get_child_element_by_text_part(text).is_element_displayed():
|
||||
self.errors.append("Newly added regular account is not shown in default key pair list")
|
||||
self.errors.append(wallet_1, "Newly added regular account is not shown in default key pair list")
|
||||
break
|
||||
expected_texts_key_pair = [
|
||||
imported_key_pair_account_name, imported_key_pair_name,
|
||||
@@ -218,7 +227,7 @@ class TestFallbackMultipleDevice(MultipleSharedDeviceTestCase):
|
||||
]
|
||||
for text in expected_texts_key_pair:
|
||||
if not wallet_1.added_key_pair_container.get_child_element_by_text_part(text).is_element_displayed():
|
||||
self.errors.append("Newly added regular account is not shown in default key pair list")
|
||||
self.errors.append(wallet_1, "Newly added regular account is not shown in default key pair list")
|
||||
break
|
||||
|
||||
wallet_1.just_fyi("Device 1: add a new key pair account by generating a new key pair")
|
||||
@@ -232,27 +241,30 @@ class TestFallbackMultipleDevice(MultipleSharedDeviceTestCase):
|
||||
|
||||
expected_addresses = generate_wallet_address(passphrase=generated_passphrase, number=4)
|
||||
if generated_key_pair_account_address != expected_addresses[0]:
|
||||
self.errors.append("Generated key pair account address %s doesn't match expected %s" % (
|
||||
self.errors.append(wallet_1, "Generated key pair account address %s doesn't match expected %s" % (
|
||||
generated_key_pair_account_address, expected_addresses[0]))
|
||||
if generated_key_pair_account_address not in expected_addresses:
|
||||
self.errors.append("Generated key pair account address %s is not in the list of expected addresses %s" % (
|
||||
generated_key_pair_account_address, expected_addresses))
|
||||
self.errors.append(wallet_1,
|
||||
"Generated key pair account address %s is not in the list of expected addresses %s" % (
|
||||
generated_key_pair_account_address, expected_addresses))
|
||||
|
||||
self.home_2.just_fyi("Device 2: check imported accounts are shown before importing key pair")
|
||||
self.home_2.profile_button.click()
|
||||
self.profile_2.profile_wallet_button.click()
|
||||
self.profile_2.key_pairs_and_accounts_button.click()
|
||||
if not self.profile_2.get_missing_key_pair_by_name(key_pair_name=imported_key_pair_name).is_element_displayed():
|
||||
self.errors.append("New imported key pair is not shown in profile as missing before importing")
|
||||
self.errors.append(self.profile_2,
|
||||
"New imported key pair is not shown in profile as missing before importing")
|
||||
if not self.profile_2.get_missing_key_pair_by_name(
|
||||
key_pair_name=generated_key_pair_name).is_element_displayed():
|
||||
self.errors.append("Generated key pair is not shown in profile as missing before importing")
|
||||
self.errors.append(self.profile_2, "Generated key pair is not shown in profile as missing before importing")
|
||||
if not self.profile_2.get_key_pair_account_by_name(account_name=regular_account_name).is_element_displayed():
|
||||
self.errors.append(
|
||||
self.profile_2,
|
||||
"Newly added regular account is not shown in profile as on device before importing key pair")
|
||||
self.profile_2.options_button.click()
|
||||
if not self.profile_2.import_by_entering_recovery_phrase_button.is_element_displayed():
|
||||
self.errors.append("Can not import key pair account from profile")
|
||||
self.errors.append(self.profile_2, "Can not import key pair account from profile")
|
||||
self.profile_2.click_system_back_button(times=4)
|
||||
|
||||
wallet_2.just_fyi("Device 2: import key pair")
|
||||
@@ -270,9 +282,11 @@ class TestFallbackMultipleDevice(MultipleSharedDeviceTestCase):
|
||||
address_text = self.profile_2.get_key_pair_account_by_name(account_name=regular_account_name).address.text
|
||||
if address_text != '...'.join((regular_account_address[:5], regular_account_address[-3:])):
|
||||
self.errors.append(
|
||||
self.profile_2,
|
||||
"Incorrect wallet address if shown for regular account after importing: " + address_text)
|
||||
else:
|
||||
self.errors.append("Newly added regular account is not shown in profile after importing key pair")
|
||||
self.errors.append(self.profile_2,
|
||||
"Newly added regular account is not shown in profile after importing key pair")
|
||||
|
||||
account_element = self.profile_2.get_key_pair_account_by_name(
|
||||
account_name=imported_key_pair_account_name)
|
||||
@@ -281,14 +295,17 @@ class TestFallbackMultipleDevice(MultipleSharedDeviceTestCase):
|
||||
if address_text != '...'.join(
|
||||
(imported_key_pair_account_address[:5], imported_key_pair_account_address[-3:])):
|
||||
self.errors.append(
|
||||
self.profile_2,
|
||||
"Incorrect wallet address if shown for imported key pair account after importing: " + address_text)
|
||||
else:
|
||||
self.errors.append(
|
||||
self.profile_2,
|
||||
"Imported key pair account is not shown in profile as on device after importing key pair")
|
||||
|
||||
if not self.profile_2.get_missing_key_pair_by_name(
|
||||
key_pair_name=generated_key_pair_name).is_element_displayed():
|
||||
self.errors.append(
|
||||
self.profile_2,
|
||||
"Generated key pair account is not shown in profile as missing after importing the first key pair")
|
||||
self.profile_2.click_system_back_button(times=3)
|
||||
|
||||
@@ -306,14 +323,15 @@ class TestFallbackMultipleDevice(MultipleSharedDeviceTestCase):
|
||||
wallet_2.about_tab.click()
|
||||
der_path = wallet_2.account_about_derivation_path_text.text
|
||||
if der_path != regular_derivation_path:
|
||||
self.errors.append("Incorrect derivation path %s is shown for the regular account" % der_path)
|
||||
self.errors.append(wallet_2, "Incorrect derivation path %s is shown for the regular account" % der_path)
|
||||
wallet_2.close_account_button.click_until_presence_of_element(account_element)
|
||||
account_element.swipe_left_on_element()
|
||||
wallet_2.get_account_element(account_name=imported_key_pair_account_name).click()
|
||||
wallet_2.about_tab.click()
|
||||
der_path = wallet_2.account_about_derivation_path_text.text
|
||||
if der_path != imported_key_pair_derivation_path:
|
||||
self.errors.append("Incorrect derivation path %s is shown for the imported key pair account" % der_path)
|
||||
self.errors.append(wallet_2,
|
||||
"Incorrect derivation path %s is shown for the imported key pair account" % der_path)
|
||||
wallet_2.close_account_button.click_until_presence_of_element(account_element)
|
||||
account_element.swipe_left_on_element()
|
||||
wallet_2.get_account_element(account_name=generated_key_pair_account_name).click()
|
||||
@@ -324,7 +342,8 @@ class TestFallbackMultipleDevice(MultipleSharedDeviceTestCase):
|
||||
wallet_2.about_tab.click()
|
||||
der_path = wallet_2.account_about_derivation_path_text.text
|
||||
if der_path != generated_key_pair_derivation_path:
|
||||
self.errors.append("Incorrect derivation path %s is shown for the generated key pair account" % der_path)
|
||||
self.errors.append(wallet_2,
|
||||
"Incorrect derivation path %s is shown for the generated key pair account" % der_path)
|
||||
if not wallet_2.element_by_text_part(generated_key_pair_account_address).is_element_displayed():
|
||||
self.errors.append(
|
||||
"Generated key pair address %s is absent in About tab" % generated_key_pair_account_address)
|
||||
@@ -345,14 +364,14 @@ class TestFallbackMultipleDevice(MultipleSharedDeviceTestCase):
|
||||
self.sign_in_2.passphrase_edit_box.send_keys(' '.join(['asset'] * 12))
|
||||
self.sign_in_2.continue_button.click()
|
||||
if not self.sign_in_2.element_by_translation_id('seed-phrase-invalid').is_element_displayed():
|
||||
self.errors.append("Error message is not displayed for invalid recovery phrase")
|
||||
self.errors.append(self.sign_in_2, "Error message is not displayed for invalid recovery phrase")
|
||||
|
||||
self.sign_in_2.just_fyi("Device 2: try creating an account with another valid passphrase")
|
||||
self.sign_in_2.passphrase_edit_box.clear()
|
||||
self.sign_in_2.passphrase_edit_box.send_keys(transaction_senders['A']['passphrase'])
|
||||
self.sign_in_2.continue_button.click()
|
||||
if not self.sign_in_2.password_input.is_element_displayed():
|
||||
self.errors.append("Can't recover an access with a valid passphrase")
|
||||
self.errors.append(self.sign_in_2, "Can't recover an access with a valid passphrase")
|
||||
self.sign_in_2.click_system_back_button(times=2)
|
||||
|
||||
self.sign_in_2.just_fyi("Device 2: try recovering an account which is already synced")
|
||||
@@ -363,9 +382,10 @@ class TestFallbackMultipleDevice(MultipleSharedDeviceTestCase):
|
||||
self.sign_in_2.native_alert_title.wait_for_element()
|
||||
shown_text = self.sign_in_2.native_alert_title.text
|
||||
if shown_text != "Keys for this account already exist":
|
||||
self.errors.append("Incorrect error message '%s' is shown for already synced account" % shown_text)
|
||||
self.errors.append(self.sign_in_2,
|
||||
"Incorrect error message '%s' is shown for already synced account" % shown_text)
|
||||
self.sign_in_2.cancel_button.click()
|
||||
except TimeoutException:
|
||||
self.errors.append("Error is not shown for already synced account")
|
||||
self.errors.append(self.sign_in_2, "Error is not shown for already synced account")
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import datetime
|
||||
import re
|
||||
import time
|
||||
|
||||
import pytest
|
||||
from _pytest.outcomes import Failed
|
||||
from selenium.common import TimeoutException, NoSuchElementException
|
||||
from selenium.common import NoSuchElementException, TimeoutException
|
||||
|
||||
from base_test_case import MultipleSharedDeviceTestCase, create_shared_drivers
|
||||
from support.api.network_api import NetworkApi
|
||||
@@ -75,8 +76,9 @@ class TestWalletMultipleDevice(MultipleSharedDeviceTestCase):
|
||||
return
|
||||
if user_name == self.receiver_username and new_eth_amount >= exp_amount:
|
||||
return
|
||||
self.errors.append(
|
||||
"Eth amount in the %s's wallet is %s but should be %s" % (user_name, new_eth_amount, exp_amount))
|
||||
self.errors.append(wallet_view,
|
||||
"Eth amount in the %s's wallet is %s but should be %s" % (
|
||||
user_name, new_eth_amount, exp_amount))
|
||||
|
||||
# ToDo: disable relogin when autoupdate feature is ready
|
||||
self.home_1.just_fyi("Relogin for getting an updated balance")
|
||||
@@ -119,10 +121,12 @@ class TestWalletMultipleDevice(MultipleSharedDeviceTestCase):
|
||||
activity_element.from_text == sender_address_short,
|
||||
activity_element.to_text == receiver_address_short)):
|
||||
self.errors.append(
|
||||
wallet_view,
|
||||
"The last transaction is not listed in activity for the %s, expected timestamp is %s" %
|
||||
('sender' if sender else 'receiver', expected_time))
|
||||
except NoSuchElementException:
|
||||
self.errors.append("Can't find the last transaction for the %s" % ('sender' if sender else 'receiver'))
|
||||
self.errors.append(wallet_view,
|
||||
"Can't find the last transaction for the %s" % ('sender' if sender else 'receiver'))
|
||||
finally:
|
||||
wallet_view.close_account_button.click_until_presence_of_element(wallet_view.show_qr_code_button)
|
||||
|
||||
@@ -141,7 +145,7 @@ class TestWalletMultipleDevice(MultipleSharedDeviceTestCase):
|
||||
device_time_before_sending = self.wallet_1.driver.device_time
|
||||
self.wallet_1.send_asset(address='arb1:' + self.receiver['wallet_address'],
|
||||
asset_name='Ether',
|
||||
amount=amount_to_send,
|
||||
amount=f"{amount_to_send:.4f}",
|
||||
network_name=self.network)
|
||||
# ToDo: Arbiscan API is down, looking for analogue
|
||||
# self.network_api.wait_for_confirmation_of_transaction(address=self.sender['wallet_address'],
|
||||
@@ -177,7 +181,7 @@ class TestWalletMultipleDevice(MultipleSharedDeviceTestCase):
|
||||
device_time_before_sending = self.wallet_1.driver.device_time
|
||||
self.wallet_1.send_asset_from_drawer(address='arb1:' + self.receiver['wallet_address'],
|
||||
asset_name='Ether',
|
||||
amount=amount_to_send,
|
||||
amount=f"{amount_to_send:.4f}",
|
||||
network_name=self.network)
|
||||
# ToDo: Arbiscan API is down, looking for analogue
|
||||
# self.network_api.wait_for_confirmation_of_transaction(address=self.sender['wallet_address'],
|
||||
@@ -207,29 +211,28 @@ class TestWalletMultipleDevice(MultipleSharedDeviceTestCase):
|
||||
class TestWalletOneDevice(MultipleSharedDeviceTestCase):
|
||||
|
||||
def prepare_devices(self):
|
||||
self.network_api = NetworkApi()
|
||||
self.drivers, self.loop = create_shared_drivers(1)
|
||||
self.sign_in_view = SignInView(self.drivers[0])
|
||||
self.sender, self.receiver = transaction_senders['ETH_1'], transaction_senders['ETH_2']
|
||||
self.total_balance = {'Ether': 0.0052, 'USDCoin': 5.0, 'Status': 10.0, 'Uniswap': 0.627, 'Dai Stablecoin': 0.0}
|
||||
self.total_balance = {'Ether': 0.0262, 'USDCoin': 5.0, 'Status': 13.0, 'Uniswap': 0.627, 'Dai Stablecoin': 0.0}
|
||||
self.mainnet_balance = {'Ether': 0.005, 'USDCoin': 0.0, 'Status': 10.0, 'Uniswap': 0.127, 'Dai Stablecoin': 0.0}
|
||||
self.optimizm_balance = {'Ether': 0.0001, 'USDCoin': 5.0, 'Status': 0, 'Uniswap': 0, 'Dai Stablecoin': 0.0}
|
||||
self.arb_balance = {'Ether': 0.0001, 'USDCoin': 0.0, 'Status': 0.0, 'Uniswap': 0.5, 'Dai Stablecoin': 0.0}
|
||||
self.optimism_balance = {'Ether': 0.0011, 'USDCoin': 5.0, 'Status': 3.0, 'Uniswap': 0, 'Dai Stablecoin': 0.0}
|
||||
self.arb_balance = {'Ether': 0.0051, 'USDCoin': 0.0, 'Status': 0.0, 'Uniswap': 0.5, 'Dai Stablecoin': 0.0}
|
||||
self.base_balance = {'Ether': 0.015, 'USDCoin': 0.0, 'Status': 0.0, 'Uniswap': 0.0, 'Dai Stablecoin': 0.0}
|
||||
self.sender['wallet_address'] = '0x' + self.sender['address']
|
||||
self.receiver['wallet_address'] = '0x' + self.receiver['address']
|
||||
self.sign_in_view.recover_access(passphrase=self.sender['passphrase'])
|
||||
|
||||
self.home_view = self.sign_in_view.get_home_view()
|
||||
self.sender_username = self.home_view.get_username()
|
||||
self.wallet_view = self.home_view.wallet_tab.click()
|
||||
|
||||
@marks.testrail_id(740490)
|
||||
def test_wallet_balance_mainnet(self):
|
||||
self.profile_view = self.home_view.profile_button.click()
|
||||
self.profile_view.switch_network()
|
||||
self.sign_in_view.sign_in(user_name=self.sender_username)
|
||||
self.sign_in_view.wallet_tab.click()
|
||||
self.wallet_view = self.home_view.wallet_tab.click()
|
||||
self.account_name = 'Account 1'
|
||||
|
||||
@marks.testrail_id(740490)
|
||||
def test_wallet_balance_mainnet(self):
|
||||
self.wallet_view.just_fyi("Checking total balance")
|
||||
real_balance = {}
|
||||
for asset in self.total_balance:
|
||||
@@ -237,12 +240,13 @@ class TestWalletOneDevice(MultipleSharedDeviceTestCase):
|
||||
|
||||
for asset in self.total_balance:
|
||||
if real_balance[asset] != self.total_balance[asset]:
|
||||
self.errors.append("For the %s the wrong value %s is shown, expected %s in total" %
|
||||
self.errors.append(self.wallet_view, "For the %s the wrong value %s is shown, expected %s in total" %
|
||||
(asset, real_balance[asset], self.total_balance[asset]))
|
||||
expected_balances = {
|
||||
'Mainnet': self.mainnet_balance,
|
||||
'Arbitrum': self.arb_balance,
|
||||
'Optimism': self.optimizm_balance
|
||||
'Optimism': self.optimism_balance,
|
||||
'Base': self.base_balance
|
||||
}
|
||||
|
||||
for network in expected_balances:
|
||||
@@ -253,14 +257,296 @@ class TestWalletOneDevice(MultipleSharedDeviceTestCase):
|
||||
real_balance[asset] = self.wallet_view.get_asset(asset).get_amount()
|
||||
for asset in expected_balances[network]:
|
||||
if real_balance[asset] != expected_balances[network][asset]:
|
||||
self.errors.append("For the %s the wrong value %s is shown, expected %s on %s" %
|
||||
self.errors.append(self.wallet_view, "For the %s the wrong value %s is shown, expected %s on %s" %
|
||||
(asset, real_balance[asset], expected_balances[network][asset], network))
|
||||
self.wallet_view.set_network_in_wallet(network)
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(741554)
|
||||
def test_wallet_send_flow_mainnet(self):
|
||||
self.wallet_view.get_account_element().click()
|
||||
self.wallet_view.send_button.click()
|
||||
self.wallet_view.address_text_input.send_keys(self.receiver['wallet_address'])
|
||||
self.wallet_view.continue_button.click()
|
||||
|
||||
asset_data = {
|
||||
'Ether': {'networks': ['Mainnet', 'Arbitrum'], 'amount': '0.00001'},
|
||||
'Status': {'networks': ['Mainnet', 'Optimism'], 'amount': '1'}
|
||||
}
|
||||
for asset, data in asset_data.items():
|
||||
for network in data['networks']:
|
||||
self.wallet_view.just_fyi("Checking the send flow for %s on %s" % (asset, network))
|
||||
self.wallet_view.select_asset(asset)
|
||||
self.wallet_view.select_network(network)
|
||||
self.wallet_view.set_amount(data['amount'])
|
||||
try:
|
||||
max_fees_text = self.wallet_view.get_data_item_element_text(data_item_name='Max fees')
|
||||
if not re.findall(r"[$]\d+.\d+", max_fees_text):
|
||||
self.errors.append(self.wallet_view,
|
||||
"%s on %s: max fee is not a number - %s" % (asset, network, max_fees_text))
|
||||
except TimeoutException:
|
||||
self.errors.append(
|
||||
self.wallet_view,
|
||||
"%s on %s: max fees is not shown before Review Send button is clicked" % (asset, network))
|
||||
|
||||
self.wallet_view.confirm_button.click()
|
||||
self.wallet_view.just_fyi("Checking Review Send page for %s on %s" % (asset, network))
|
||||
|
||||
expected_amount = "%s %s" % (data['amount'], 'ETH' if asset == 'Ether' else 'SNT')
|
||||
sender_short_address = self.sender['wallet_address'].replace(self.sender['wallet_address'][6:-3],
|
||||
'…').lower()
|
||||
receiver_short_address = self.receiver['wallet_address'].replace(self.receiver['wallet_address'][6:-3],
|
||||
'…').lower()
|
||||
for text in [self.account_name, sender_short_address, expected_amount]:
|
||||
if not self.wallet_view.from_data_container.get_child_element_by_text(text).is_element_displayed():
|
||||
self.errors.append(
|
||||
self.wallet_view,
|
||||
"%s on %s: text %s is not shown in 'From' container on the Review Send page" % (
|
||||
asset, network, text))
|
||||
for text in [receiver_short_address, expected_amount]:
|
||||
if not self.wallet_view.to_data_container.get_child_element_by_text(text).is_element_displayed():
|
||||
self.errors.append(
|
||||
self.wallet_view,
|
||||
"%s on %s: text %s is not shown in 'To' container on the Review Send page" % (
|
||||
asset, network, text))
|
||||
|
||||
data_to_check = {
|
||||
'Est. time': ' min',
|
||||
'Max fees': r"[$]\d+.\d+",
|
||||
'Recipient gets': expected_amount
|
||||
}
|
||||
for key, expected_value in data_to_check.items():
|
||||
try:
|
||||
text = self.wallet_view.get_data_item_element_text(data_item_name=key)
|
||||
if key == 'Max fees':
|
||||
if not re.findall(expected_value, text):
|
||||
self.errors.append(self.wallet_view,
|
||||
"%s on %s: max fee is not a number - %s on the Review Send page" % (
|
||||
asset, network, text))
|
||||
else:
|
||||
if text != expected_value:
|
||||
self.errors.append(
|
||||
self.wallet_view,
|
||||
"%s on %s: %s text %s doesn't match expected %s on the Review Send page" % (
|
||||
asset, network, key, text, expected_value))
|
||||
except TimeoutException:
|
||||
self.errors.append(self.wallet_view,
|
||||
"%s on %s: %s is not shown on the Review Send page" % (asset, network, key))
|
||||
|
||||
self.wallet_view.slide_button_track.slide()
|
||||
if not self.wallet_view.password_input.is_element_displayed():
|
||||
self.errors.append("%s on %s: can't confirm transaction" % (asset, network))
|
||||
self.wallet_view.click_system_back_button_until_presence_of_element(
|
||||
element=self.wallet_view.element_by_text('Select token'), attempts=4)
|
||||
self.wallet_view.click_system_back_button_until_presence_of_element(
|
||||
element=self.wallet_view.add_account_button, attempts=6)
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(741555)
|
||||
def test_wallet_swap_flow_mainnet(self):
|
||||
self.wallet_view.navigate_back_to_wallet_view()
|
||||
self.wallet_view.get_account_element().click()
|
||||
self.wallet_view.swap_button.click()
|
||||
for network in ['Mainnet', 'Optimism']:
|
||||
self.wallet_view.just_fyi("Checking the Swap flow for SNT on %s" % network)
|
||||
self.wallet_view.select_asset('Status')
|
||||
self.wallet_view.select_network(network)
|
||||
self.wallet_view.set_amount('1')
|
||||
data_to_check = {
|
||||
'Max fees': r"[$]\d+.\d+",
|
||||
'Max slippage': r"\d+.\d+[%]"
|
||||
}
|
||||
for key, expected_value in data_to_check.items():
|
||||
try:
|
||||
text = self.wallet_view.get_data_item_element_text(data_item_name=key)
|
||||
if not re.findall(expected_value, text):
|
||||
self.errors.append(self.wallet_view,
|
||||
"%s: %s is not a number - %s before pressing Review Swap button" % (
|
||||
network, key, text))
|
||||
except TimeoutException:
|
||||
self.errors.append(self.wallet_view,
|
||||
"%s: %s is not shown before pressing Review Swap button" % (network, key))
|
||||
|
||||
try:
|
||||
self.wallet_view.wait_for_swap_input_to_be_shown()
|
||||
except TimeoutException:
|
||||
self.errors.append(self.wallet_view, "%s: ETH amount is not displayed")
|
||||
continue
|
||||
self.wallet_view.approve_swap_button.click()
|
||||
self.wallet_view.just_fyi("Checking 'Set Spending Cap' screen for %s" % network)
|
||||
if not self.wallet_view.spending_cap_approval_info_container.get_child_element_by_text(
|
||||
'1 SNT').is_element_displayed():
|
||||
self.errors.append(self.wallet_view,
|
||||
"%s: Spending cap is not shown on the 'Set Spending Cap' screen" % network)
|
||||
for text in [self.account_name,
|
||||
self.sender['wallet_address'].replace(self.sender['wallet_address'][5:-3], '...').lower()]:
|
||||
if not self.wallet_view.account_approval_info_container.get_child_element_by_text(
|
||||
text).is_element_displayed():
|
||||
self.errors.append(
|
||||
self.wallet_view,
|
||||
"%s: Text %s is not shown for the account on the 'Set Spending Cap' screen" % (network, text))
|
||||
if not self.wallet_view.token_approval_info_container.get_child_element_by_text(
|
||||
'SNT').is_element_displayed():
|
||||
self.errors.append(self.wallet_view,
|
||||
"%s: Token is not shown on the 'Set Spending Cap' screen" % network)
|
||||
if not self.wallet_view.spender_contract_approval_info_container.is_element_displayed():
|
||||
self.errors.append(self.wallet_view,
|
||||
"%s: Spender contract info is missing on the 'Set Spending Cap' screen" % network)
|
||||
|
||||
data_to_check = {
|
||||
'Network': network,
|
||||
# 'Max fees': r"[$]\d+.\d+", # ToDO: enable when https://github.com/status-im/status-mobile/issues/21948 is fixed
|
||||
# 'Est. time': ' min',
|
||||
}
|
||||
for key, expected_value in data_to_check.items():
|
||||
try:
|
||||
text = self.wallet_view.get_data_item_element_text(data_item_name=key)
|
||||
if key == 'Max fees':
|
||||
if not re.findall(expected_value, text):
|
||||
self.errors.append(self.wallet_view,
|
||||
"%s: max fee is not a number - %s on the 'Set Spending Cap' screen" % (
|
||||
network, text))
|
||||
else:
|
||||
if text != expected_value:
|
||||
self.errors.append(
|
||||
self.wallet_view,
|
||||
"%s: %s text %s doesn't match expected %s on the 'Set Spending Cap' screen" % (
|
||||
network, key, text, expected_value))
|
||||
except (TimeoutException, NoSuchElementException):
|
||||
self.errors.append(self.wallet_view,
|
||||
"%s: %s is not shown on the 'Set Spending Cap' screen" % (network, key))
|
||||
try:
|
||||
self.wallet_view.slide_button_track.slide()
|
||||
if not self.wallet_view.password_input.is_element_displayed():
|
||||
self.errors.append(self.wallet_view, "%s: can't sign swap" % network)
|
||||
except NoSuchElementException:
|
||||
self.errors.append(self.wallet_view, "%s: can't sign swap" % network)
|
||||
|
||||
self.wallet_view.click_system_back_button_until_presence_of_element(
|
||||
element=self.wallet_view.element_by_text('Select asset to pay'), attempts=4)
|
||||
self.wallet_view.click_system_back_button_until_presence_of_element(
|
||||
element=self.wallet_view.add_account_button, attempts=6)
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(741612)
|
||||
def test_wallet_bridge_flow_mainnet(self):
|
||||
self.wallet_view.navigate_back_to_wallet_view()
|
||||
self.wallet_view.get_account_element().click()
|
||||
self.wallet_view.bridge_button.click()
|
||||
networks = {'Optimism': 'Arbitrum', 'Arbitrum': 'Base', 'Base': 'Optimism'}
|
||||
amount = '0.001'
|
||||
for network_from, network_to in networks.items():
|
||||
self.wallet_view.just_fyi("Checking bridge from %s to %s" % (network_from, network_to))
|
||||
self.wallet_view.select_asset('Ether')
|
||||
self.wallet_view.select_network(network_from)
|
||||
self.wallet_view.select_network(network_to)
|
||||
self.wallet_view.set_amount(amount)
|
||||
data_to_check = {
|
||||
'Max fees': r"[$]\d+.\d+",
|
||||
'Bridged to %s' % network_to: r"0.000\d+ ETH"
|
||||
}
|
||||
for key, expected_value in data_to_check.items():
|
||||
try:
|
||||
text = self.wallet_view.get_data_item_element_text(data_item_name=key)
|
||||
if not re.findall(expected_value, text):
|
||||
self.errors.append(self.wallet_view,
|
||||
"%s to %s: %s is not a number - %s before pressing Review Bridge button" % (
|
||||
network_from, network_to, key, text))
|
||||
except TimeoutException:
|
||||
self.errors.append(self.wallet_view,
|
||||
"%s to %s: %s is not shown before pressing Review Bridge button" % (
|
||||
network_from, network_to, key))
|
||||
self.wallet_view.just_fyi("Checking routes from %s to %s" % (network_from, network_to))
|
||||
try:
|
||||
element = self.wallet_view.get_route_element('from')
|
||||
element.wait_for_element()
|
||||
shown_amount = element.amount_text
|
||||
if shown_amount != amount + ' ETH':
|
||||
self.errors.append(self.wallet_view, "%s to %s: 'From' route amount %s doesn't match expected %s" %
|
||||
(network_from, network_to, shown_amount, amount + ' ETH'))
|
||||
shown_network = element.network_text
|
||||
if shown_network != network_from:
|
||||
self.errors.append(self.wallet_view, "%s to %s: 'From' route network %s doesn't match expected %s" %
|
||||
(network_from, network_to, shown_network, network_from))
|
||||
except TimeoutException:
|
||||
self.errors.append(self.wallet_view, "%s to %s: 'From' route is not shown" % (network_from, network_to))
|
||||
|
||||
try:
|
||||
element = self.wallet_view.get_route_element('to')
|
||||
element.wait_for_element()
|
||||
shown_amount = element.amount_text
|
||||
if not re.findall(r"0.000\d+ ETH", shown_amount):
|
||||
self.errors.append(self.wallet_view, "%s to %s: 'To' route amount %s is not a number" %
|
||||
(network_from, network_to, shown_amount))
|
||||
shown_network = element.network_text
|
||||
if shown_network != network_to:
|
||||
self.errors.append(self.wallet_view, "%s to %s: 'To' route network %s doesn't match expected %s" %
|
||||
(network_from, network_to, shown_network, network_to))
|
||||
except TimeoutException:
|
||||
self.errors.append(self.wallet_view, "%s to %s: 'To' route is not shown" % (network_from, network_to))
|
||||
|
||||
self.wallet_view.confirm_button.click()
|
||||
self.wallet_view.just_fyi("Checking Bridge screen from %s to %s" % (network_from, network_to))
|
||||
containers = {'from': self.wallet_view.from_data_container, 'to': self.wallet_view.to_data_container}
|
||||
for name, container in containers.items():
|
||||
try:
|
||||
container.wait_for_element()
|
||||
for text in [self.account_name,
|
||||
self.sender['wallet_address'].replace(self.sender['wallet_address'][6:-3],
|
||||
'…').lower()]:
|
||||
if not container.get_child_element_by_text(text).is_element_displayed():
|
||||
self.errors.append(
|
||||
self.wallet_view,
|
||||
"%s to %s: Text %s is not shown in the '%s' data container on the Review Bridge screen"
|
||||
% (network_from, network_to, text, name))
|
||||
amount_text = container.amount_text
|
||||
if name == 'from' and amount_text != amount + ' ETH':
|
||||
self.errors.append(
|
||||
self.wallet_view,
|
||||
"%s to %s: amount %s in the 'from' data container doesn't match expected %s ETH"
|
||||
% (network_from, network_to, amount_text, amount))
|
||||
if name == 'to' and not re.findall(r"0.000\d+ ETH", amount_text):
|
||||
self.errors.append(
|
||||
self.wallet_view,
|
||||
"%s to %s: amount %s in the 'to' data container is not a number"
|
||||
% (network_from, network_to, amount_text))
|
||||
except TimeoutException:
|
||||
self.errors.append(self.wallet_view, "%s to %s: data '%s' is not shown in Review Bridge screen" %
|
||||
(network_from, network_to, name))
|
||||
if network_to == 'Arbitrum':
|
||||
network_to_short_name = 'Arb1.'
|
||||
elif network_to == 'Optimism':
|
||||
network_to_short_name = 'Oeth.'
|
||||
else:
|
||||
network_to_short_name = network_to
|
||||
data_to_check = {
|
||||
'Est. time': ' min',
|
||||
'Max fees': r"[$]\d+.\d+",
|
||||
'Bridged to %s' % network_to_short_name: r"0.000\d+ ETH"
|
||||
}
|
||||
for key, expected_value in data_to_check.items():
|
||||
try:
|
||||
text = self.wallet_view.get_data_item_element_text(data_item_name=key)
|
||||
if not re.findall(expected_value, text):
|
||||
self.errors.append(self.wallet_view,
|
||||
"%s to %s: %s has incorrect value - %s on the Review Bridge screen" % (
|
||||
network_from, network_to, key, text))
|
||||
except TimeoutException:
|
||||
self.errors.append(self.wallet_view,
|
||||
"%s to %s: %s is not shown on the Review Bridge screen" % (
|
||||
network_from, network_to, key))
|
||||
self.wallet_view.slide_button_track.slide()
|
||||
if not self.wallet_view.password_input.is_element_displayed():
|
||||
self.errors.append("%s to %s: can't confirm bridge" % (network_from, network_to))
|
||||
self.wallet_view.click_system_back_button(times=5)
|
||||
self.wallet_view.click_system_back_button_until_presence_of_element(
|
||||
element=self.wallet_view.add_account_button, attempts=6)
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(727231)
|
||||
def test_wallet_add_remove_regular_account(self):
|
||||
self.wallet_view.navigate_back_to_wallet_view()
|
||||
self.wallet_view.just_fyi("Adding new regular account")
|
||||
new_account_name = "New Account"
|
||||
self.wallet_view.add_regular_account(account_name=new_account_name)
|
||||
@@ -273,17 +559,18 @@ class TestWalletOneDevice(MultipleSharedDeviceTestCase):
|
||||
self.wallet_view.just_fyi("Checking that the new wallet is added to the Share QR Code menu")
|
||||
self.home_view.show_qr_code_button.click()
|
||||
self.home_view.share_wallet_tab_button.click()
|
||||
if self.home_view.account_name_text.text != 'Account 1':
|
||||
self.errors.append("Incorrect first account is shown on Share QR Code menu")
|
||||
if self.home_view.account_name_text.text != self.account_name:
|
||||
self.errors.append(self.home_view, "Incorrect first account is shown on Share QR Code menu")
|
||||
self.home_view.qr_code_image_element.swipe_left_on_element()
|
||||
try:
|
||||
self.home_view.account_name_text.wait_for_element_text(text=new_account_name, wait_time=3)
|
||||
except Failed:
|
||||
self.errors.append("Can't swipe between accounts, newly added account is not shown")
|
||||
self.errors.append(self.home_view, "Can't swipe between accounts, newly added account is not shown")
|
||||
else:
|
||||
shown_address = self.home_view.copy_wallet_address()
|
||||
if set(shown_address.split(':')) != set(new_wallet_address.split(':')):
|
||||
self.errors.append(
|
||||
self.home_view,
|
||||
"Incorrect address '%s' is shown when swiping between accounts, expected one is '%s'" % (
|
||||
shown_address, new_wallet_address))
|
||||
self.home_view.click_system_back_button()
|
||||
@@ -292,9 +579,9 @@ class TestWalletOneDevice(MultipleSharedDeviceTestCase):
|
||||
if self.wallet_view.get_account_element(account_name=new_account_name).is_element_displayed():
|
||||
self.wallet_view.remove_account(account_name=new_account_name)
|
||||
if self.wallet_view.get_account_element(account_name=new_account_name).is_element_displayed():
|
||||
self.errors.append("Account was not removed from wallet")
|
||||
self.errors.append(self.wallet_view, "Account was not removed from wallet")
|
||||
else:
|
||||
self.errors.append("Newly added account is not shown in the accounts list")
|
||||
self.errors.append(self.wallet_view, "Newly added account is not shown in the accounts list")
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@@ -315,13 +602,13 @@ class TestWalletOneDevice(MultipleSharedDeviceTestCase):
|
||||
self.wallet_view.just_fyi("Checking that the new wallet is added to the Share QR Code menu")
|
||||
self.home_view.show_qr_code_button.click()
|
||||
self.home_view.share_wallet_tab_button.click()
|
||||
if self.home_view.account_name_text.text != 'Account 1':
|
||||
self.errors.append("Incorrect first account is shown on Share QR Code menu")
|
||||
if self.home_view.account_name_text.text != self.account_name:
|
||||
self.errors.append(self.home_view, "Incorrect first account is shown on Share QR Code menu")
|
||||
self.home_view.qr_code_image_element.swipe_left_on_element()
|
||||
try:
|
||||
self.home_view.account_name_text.wait_for_element_text(text=new_account_name, wait_time=3)
|
||||
except Failed:
|
||||
self.errors.append("Can't swipe between accounts, account to watch is not shown")
|
||||
self.errors.append(self.home_view, "Can't swipe between accounts, account to watch is not shown")
|
||||
else:
|
||||
shown_address = self.home_view.copy_wallet_address()
|
||||
if set(shown_address.split(':')) != {'eth', 'arb1', 'oeth', address_to_watch}:
|
||||
@@ -334,8 +621,8 @@ class TestWalletOneDevice(MultipleSharedDeviceTestCase):
|
||||
if self.wallet_view.get_account_element(account_name=new_account_name).is_element_displayed():
|
||||
self.wallet_view.remove_account(account_name=new_account_name, watch_only=True)
|
||||
if self.wallet_view.get_account_element(account_name=new_account_name).is_element_displayed():
|
||||
self.errors.append("Account was not removed from wallet")
|
||||
self.errors.append(self.wallet_view, "Account was not removed from wallet")
|
||||
else:
|
||||
self.errors.append("Watch only account is not shown in the accounts list")
|
||||
self.errors.append(self.wallet_view, "Watch only account is not shown in the accounts list")
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@@ -201,7 +201,7 @@ class BaseView(object):
|
||||
for _ in range(times):
|
||||
self.driver.press_keycode(4)
|
||||
|
||||
def _navigate_back_to_view(self, element, attempts=3):
|
||||
def click_system_back_button_until_presence_of_element(self, element, attempts=3):
|
||||
counter = 0
|
||||
while not element.is_element_displayed(1) and counter <= attempts:
|
||||
self.driver.press_keycode(4)
|
||||
@@ -218,14 +218,14 @@ class BaseView(object):
|
||||
or not self.community_floating_screen.is_element_disappeared(1) \
|
||||
or not self.discover_communities_floating_screen.is_element_disappeared(1):
|
||||
self.driver.press_keycode(4)
|
||||
self._navigate_back_to_view(self.chats_tab)
|
||||
self.click_system_back_button_until_presence_of_element(self.chats_tab)
|
||||
|
||||
def navigate_back_to_chat_view(self):
|
||||
self._navigate_back_to_view(self.get_chat_view().chat_message_input)
|
||||
self.click_system_back_button_until_presence_of_element(self.get_chat_view().chat_message_input)
|
||||
|
||||
def navigate_back_to_wallet_view(self, attempts=3):
|
||||
element = self.get_wallet_view().network_drop_down
|
||||
self._navigate_back_to_view(element)
|
||||
self.click_system_back_button_until_presence_of_element(element)
|
||||
|
||||
def click_system_home_button(self):
|
||||
self.driver.info('Press system Home button')
|
||||
|
||||
@@ -247,7 +247,9 @@ class HomeView(BaseView):
|
||||
def __init__(self, driver):
|
||||
super().__init__(driver)
|
||||
|
||||
self.plus_button = Button(self.driver, accessibility_id="new-chat-button")
|
||||
self.skip_editing_profile_button = Button(self.driver, xpath="//*[@content-desc='button-two']//*[@text='Skip']")
|
||||
self.edit_profile_button = Button(self.driver, xpath="//*[@content-desc='button-one']//*[@text='Edit Profile']")
|
||||
self.submit_create_profile_button = Button(self.driver, accessibility_id="submit-create-profile-button")
|
||||
self.plus_community_button = Button(self.driver, accessibility_id="new-communities-button")
|
||||
self.chat_name_text = Text(self.driver, accessibility_id="chat-name-text")
|
||||
self.start_new_chat_button = ChatButton(self.driver, accessibility_id="start-1-1-chat-button")
|
||||
@@ -377,7 +379,7 @@ class HomeView(BaseView):
|
||||
if self.toast_content_element.is_element_displayed(10):
|
||||
self.toast_content_element.wait_for_invisibility_of_element()
|
||||
try:
|
||||
self.notifications_unread_badge.wait_for_visibility_of_element(60)
|
||||
self.notifications_unread_badge.wait_for_visibility_of_element(120)
|
||||
except TimeoutException:
|
||||
pass
|
||||
self.open_activity_center_button.click_until_presence_of_element(self.close_activity_centre)
|
||||
@@ -400,9 +402,15 @@ class HomeView(BaseView):
|
||||
self.close_activity_centre.wait_for_rendering_ended_and_click()
|
||||
self.chats_tab.wait_for_visibility_of_element()
|
||||
|
||||
def add_contact(self, public_key, nickname=''):
|
||||
def add_contact(self, public_key, username='', nickname=''):
|
||||
self.driver.info("Adding user to Contacts via chats > add new contact")
|
||||
self.new_chat_button.click_until_presence_of_element(self.add_a_contact_chat_bottom_sheet_button)
|
||||
self.new_chat_button.click()
|
||||
if username:
|
||||
self.edit_profile_button.click()
|
||||
self.get_sign_in_view().profile_title_input.send_keys(username)
|
||||
self.submit_create_profile_button.click()
|
||||
else:
|
||||
self.skip_editing_profile_button.click_if_shown()
|
||||
self.add_a_contact_chat_bottom_sheet_button.click()
|
||||
|
||||
chat = self.get_chat_view()
|
||||
|
||||
@@ -59,6 +59,17 @@ class ActivityElement(BaseElement):
|
||||
xpath="//*[@content-desc='context-tag'][3]/android.widget.TextView").text
|
||||
|
||||
|
||||
class ConfirmationViewInfoContainer(BaseElement):
|
||||
|
||||
def __init__(self, driver, label_name: str):
|
||||
self.locator = "//*[@content-desc='summary-%s-label']/following-sibling::android.view.ViewGroup[1]" % label_name
|
||||
super().__init__(driver, xpath=self.locator)
|
||||
|
||||
@property
|
||||
def amount_text(self):
|
||||
return Text(self.driver, xpath=self.locator + "/*[@content-desc='networks']/android.widget.TextView").text
|
||||
|
||||
|
||||
class WalletView(BaseView):
|
||||
def __init__(self, driver):
|
||||
super().__init__(driver)
|
||||
@@ -84,6 +95,8 @@ class WalletView(BaseView):
|
||||
self.driver, xpath="//*[@content-desc='account-avatar']/../following-sibling::android.widget.TextView[1]")
|
||||
self.account_emoji_button = Button(self.driver, accessibility_id='account-emoji')
|
||||
self.send_button = Button(self.driver, accessibility_id='send')
|
||||
self.swap_button = Button(self.driver, accessibility_id='swap')
|
||||
self.bridge_button = Button(self.driver, accessibility_id='bridge')
|
||||
self.send_from_drawer_button = Button(
|
||||
self.driver, xpath="//*[@content-desc='send']/*[@content-desc='left-icon-for-action']")
|
||||
self.copy_address_button = Button(self.driver, accessibility_id='copy-address')
|
||||
@@ -104,6 +117,25 @@ class WalletView(BaseView):
|
||||
self.confirm_button = Button(self.driver, accessibility_id='button-one')
|
||||
self.done_button = Button(self.driver, accessibility_id='done')
|
||||
|
||||
# Review Send and Review Bridge screens
|
||||
self.from_data_container = ConfirmationViewInfoContainer(self.driver, label_name='from')
|
||||
self.to_data_container = ConfirmationViewInfoContainer(self.driver, label_name='to')
|
||||
|
||||
# Swap flow
|
||||
self.approve_swap_button = Button(self.driver, accessibility_id='Approve')
|
||||
self.spending_cap_approval_info_container = BaseElement(
|
||||
self.driver,
|
||||
xpath="//*[@content-desc='spending-cap-label']/following-sibling::*[@content-desc='approval-info'][1]")
|
||||
self.account_approval_info_container = BaseElement(
|
||||
self.driver,
|
||||
xpath="//*[@content-desc='account-label']/following-sibling::*[@content-desc='approval-info'][1]")
|
||||
self.token_approval_info_container = BaseElement(
|
||||
self.driver,
|
||||
xpath="//*[@content-desc='token-label']/following-sibling::*[@content-desc='approval-info'][1]")
|
||||
self.spender_contract_approval_info_container = BaseElement(
|
||||
self.driver,
|
||||
xpath="//*[@content-desc='spender-contract-label']/following-sibling::*[@content-desc='approval-info'][1]")
|
||||
|
||||
# Edit key pair
|
||||
self.edit_key_pair_button = Button(self.driver, accessibility_id="Edit")
|
||||
self.key_pairs_plus_button = Button(self.driver, accessibility_id="standard-title-action")
|
||||
@@ -156,11 +188,11 @@ class WalletView(BaseView):
|
||||
self.confirm_button.click()
|
||||
self.slide_and_confirm_with_password()
|
||||
|
||||
def set_amount(self, amount: float):
|
||||
for i in '{:f}'.format(amount).rstrip('0'):
|
||||
def set_amount(self, amount: str):
|
||||
for i in amount:
|
||||
Button(self.driver, accessibility_id='keyboard-key-%s' % i).click()
|
||||
|
||||
def send_asset(self, address: str, asset_name: str, amount: float, network_name: str):
|
||||
def send_asset(self, address: str, asset_name: str, amount: str, network_name: str):
|
||||
self.send_button.click()
|
||||
self.address_text_input.send_keys(address)
|
||||
self.continue_button.click()
|
||||
@@ -169,7 +201,7 @@ class WalletView(BaseView):
|
||||
self.set_amount(amount)
|
||||
self.confirm_transaction()
|
||||
|
||||
def send_asset_from_drawer(self, address: str, asset_name: str, amount: float, network_name: str):
|
||||
def send_asset_from_drawer(self, address: str, asset_name: str, amount: str, network_name: str):
|
||||
asset_element = self.get_asset(asset_name)
|
||||
asset_element.long_press_without_release()
|
||||
self.send_from_drawer_button.double_click()
|
||||
@@ -250,3 +282,30 @@ class WalletView(BaseView):
|
||||
wallet_address = self.sharing_text_native.text
|
||||
self.click_system_back_button()
|
||||
return wallet_address
|
||||
|
||||
def get_data_item_element_text(self, data_item_name: str):
|
||||
element = Text(self.driver, xpath="//*[@text='%s']/following-sibling::android.widget.TextView" % data_item_name)
|
||||
element.wait_for_element(15)
|
||||
return element.text
|
||||
|
||||
def wait_for_swap_input_to_be_shown(self):
|
||||
locator = "//*[@content-desc='swap-input'][2]//*[@content-desc='token-avatar']" \
|
||||
"/following-sibling::*//*[starts-with(@text,'0.000')]"
|
||||
BaseElement(self.driver, xpath=locator).wait_for_visibility_of_element()
|
||||
|
||||
def get_route_element(self, route_name: str):
|
||||
class RouteElement(BaseElement):
|
||||
def __init__(self, driver, route_name):
|
||||
self.locator = "//*[@text='%s']/following-sibling::*[@content-desc='container'][%s]" % (
|
||||
route_name.capitalize(), 1 if route_name == 'from' else 2)
|
||||
super().__init__(driver, xpath=self.locator)
|
||||
|
||||
@property
|
||||
def amount_text(self):
|
||||
return Text(self.driver, xpath="(%s//android.widget.TextView)[1]" % self.locator).text
|
||||
|
||||
@property
|
||||
def network_text(self):
|
||||
return Text(self.driver, xpath="(%s//android.widget.TextView)[2]" % self.locator).text
|
||||
|
||||
return RouteElement(self.driver, route_name)
|
||||
|
||||
+15
-1
@@ -59,9 +59,9 @@
|
||||
"add-bootnode": "Add bootnode",
|
||||
"add-contact": "Add contact",
|
||||
"add-custom-token": "Add custom token",
|
||||
"add-display-name-and-picture": "Add an optional display name and profile picture so others can easily recognize you",
|
||||
"add-eth": "Add ETH",
|
||||
"add-favourite": "Add favourite",
|
||||
"add-key-pair-desktop": "To add existing key pair to the Keycard please use Status Desktop. If you'd like this feature on mobile, feel free to upvote them.",
|
||||
"add-mailserver": "Add Status node",
|
||||
"add-me-to-your-contacts": "Please add me to your contacts",
|
||||
"add-members": "Add members",
|
||||
@@ -184,7 +184,11 @@
|
||||
"back-up-your-seed-phrase": "Backup your recovery phrase",
|
||||
"backing-up": "Backing up...",
|
||||
"backup-disabled": "Disabled",
|
||||
"backup-empty-keycard-only": "You can only back up to an empty Keycard.",
|
||||
"backup-enabled": "Enabled",
|
||||
"backup-keycard": "Backup Keycard",
|
||||
"backup-keycard-created": "Backup Keycard successfully created",
|
||||
"backup-keycard-instructions": "You’ll need an empty Keycard to create backup. You’ll be able to create a different PIN for backup Keycard. It might make sense to mark your Keycards, so you don’t mix them up.",
|
||||
"backup-recovery-phrase": "Backup recovery phrase",
|
||||
"backup-recovery-phrase-description": "Save in a secure place that only you control, these 12 words give access to all of your funds.",
|
||||
"backup-settings": "Backup settings",
|
||||
@@ -547,6 +551,8 @@
|
||||
"create-a-pin": "Create a 6-digit passcode",
|
||||
"create-a-puk": "Create a 12-digit PUK",
|
||||
"create-account": "Create account",
|
||||
"create-backup-keycard": "Create backup Keycard",
|
||||
"create-backup-profile-keycard": "Create backup for your profile Keycard",
|
||||
"create-category": "Create category",
|
||||
"create-channel": "Create a channel",
|
||||
"create-channel-title": "New channel",
|
||||
@@ -1227,6 +1233,7 @@
|
||||
"import-private-key": "Import private key",
|
||||
"import-private-key-info": "New addresses cannot be derived from an account imported from a private key. Import using a seed phrase if you wish to derive addresses.",
|
||||
"import-profile-key-pair": "Import profile key pair",
|
||||
"import-recovery-phrase-to-keycard": "Import recovery phrase to Keycard",
|
||||
"import-to-use-derived-accounts": "Import to use derived accounts",
|
||||
"import-using-phrase": "Import using recovery phrase",
|
||||
"in": "in",
|
||||
@@ -1348,6 +1355,7 @@
|
||||
"joined-group-chat-description": "You've joined {{group-name}} from invitation by {{username}}",
|
||||
"jul": "Jul",
|
||||
"jun": "Jun",
|
||||
"just-introduce-yourself": "Introduce yourself",
|
||||
"K": "K",
|
||||
"keep-card-steady": "Keep the card steady under the phone",
|
||||
"keep-key": "KeepKey",
|
||||
@@ -1381,6 +1389,7 @@
|
||||
"keycard-connected-title": "Connected",
|
||||
"keycard-contains-key-pair": "Keycard contains your profile key pair",
|
||||
"keycard-desc": "Own a Keycard? Store your keys on it; you’ll need it for transactions",
|
||||
"keycard-documentation": "Keycard is a hardware wallet in a credit-card sized smartcard that works with the Status app. You can store your Status keys and sign transactions securely with it.\n\nKeycard is designed to be mobile-friendly and uses contactless NFC technology to communicate with your phone, so you can sign transactions with just a tap of the card. It is lightweight, convenient, and can fit in your wallet, pocket, or phone case.\n\nProtect your assets and accounts with the Keycard, a cold storage hardware wallet that provides a contactless and convenient experience.",
|
||||
"keycard-dont-ask-card": "Don't ask for card to sign in",
|
||||
"keycard-empty": "Keycard is empty",
|
||||
"keycard-empty-ready": "Keycard is empty and ready to be used",
|
||||
@@ -1558,6 +1567,7 @@
|
||||
"make-sure-keycard": "Make sure the card you scanned is a Keycard.",
|
||||
"make-sure-no-camera-warning": "Make sure no camera or person can see this screen before revealing",
|
||||
"manage-connections": "Manage connections from within Application Connections",
|
||||
"manage-keycard": "Manage Keycard",
|
||||
"manage-keys-and-storage": "Manage keys and storage",
|
||||
"manage-members": "Manage members",
|
||||
"manage-tokens": "Manage tokens",
|
||||
@@ -2257,6 +2267,7 @@
|
||||
"say-hi": "Say hi",
|
||||
"scan-an-account-qr-code": "Scan an account QR code",
|
||||
"scan-an-address-qr-code": "Scan an address QR code",
|
||||
"scan-empty-keycard": "Scan empty Keycard",
|
||||
"scan-key-pairs-qr-code": "Scan key pairs QR code",
|
||||
"scan-keycard": "Scan Keycard",
|
||||
"scan-keycard-actions": "Scan Keycard to see available actions",
|
||||
@@ -2374,6 +2385,7 @@
|
||||
"settings": "Settings",
|
||||
"setup-group-chat": "Setup group chat",
|
||||
"setup-keycard": "Setup Keycard",
|
||||
"setup-keycard-description": "Set up your Keycard to log in, sign transactions, create backups and much more.",
|
||||
"setup-syncing": "Pair devices to sync",
|
||||
"share": "Share",
|
||||
"share-account": "Share account",
|
||||
@@ -2519,6 +2531,7 @@
|
||||
"sticker-market": "Sticker market",
|
||||
"storage": "Storage",
|
||||
"store-confirmations": "Store confirmations",
|
||||
"store-key-pair-on-keycard": "Store your existing key pair on Keycard",
|
||||
"store-your-asets-on-keycard": "Store your assets on Keycard",
|
||||
"strength-divider-okay-label": "Okay",
|
||||
"strength-divider-strong-label": "Strong",
|
||||
@@ -2774,6 +2787,7 @@
|
||||
"use-an-empty-keycard": "Use an empty Keycard",
|
||||
"use-an-empty-keycard-subtitle": "Store your new profile keys on Keycard",
|
||||
"use-as-profile-picture": "Use as profile picture",
|
||||
"use-backup-keycard": "Use as backup Keycard",
|
||||
"use-biometrics": "Use biometrics to fill in your password",
|
||||
"use-keycard": "Use Keycard",
|
||||
"use-keycard-for-status": "From now on, use this Keycard to login to Status and transact with derived accounts on all synced devices. To start using it, logout and log back in with this Keycard.",
|
||||
|
||||
Reference in New Issue
Block a user