Compare commits

...
Author SHA1 Message Date
Yevheniia Berdnyk 579fde7f56 e2e: temp, will be deleted 2025-01-31 17:53:08 +02:00
Yevheniia Berdnyk 5ff1c8f1e4 e2e: added wallet test for bridge flow 2025-01-30 20:13:34 +02:00
Brian Sztamfater 7289940653 fix: swap fees are not displayed if route estimated time is nil (#22001)
Signed-off-by: Brian Sztamfater <brian@status.im>
2025-01-30 10:08:37 -03:00
Yevheniia Berdnyk a253f8cedb e2e: updated tests with editing profile when starting chat 2025-01-30 11:49:58 +02:00
Ulises Manuel daf52102ce feat(onboarding): ask user to update their profile (#21862)
* Add `buttons-style` prop to bottom actions to allow same button dimensions

* Make events to update a profile more generic

* Fix tests

* Add modal screen to update the profile

* Add introduce yourself modal

* Ask user to update their profile before sending a message or contact request

* Fix color picker selected styles

* Remove some `:f>` now unnecessary

* No longer shows the modal if the user manually updates their profile
2025-01-29 19:50:01 -06:00
Yevheniia Berdnyk fa20d4d9c3 e2e: added wallet tests for send and swap flows on mainnet 2025-01-29 18:32:03 +02:00
Parvesh Monu dd26fcf42c Add Documentation drawer on Check your Keycard screen (#21997) 2025-01-29 19:25:34 +05:30
Lungu Cristian 8ac9cc08e1 Keycard signing for dapp interactions (#21785)
* feat: wip dapps signing with keycard

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* fix: hide the pin sheet before showing the connection sheet

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* fix: signing dapp request with password

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* fix: logic for getting the current dapp

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* fix: issues after endpoints update

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* feat: removed support for eth_sign and signTransaction

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* fix: removed unused event

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* feat: re-enable dapps interactions with keycard

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* fix: adapted to latest standard-auth changes

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* feat: enable connected dapps for keycard

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* ref: removed threading (->)

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* fix: get keycard keypair addresses manually

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>

* fix: wrong condition on utils/keycard-address?

---------

Signed-off-by: Cristian Lungu <lungucristian95@gmail.com>
2025-01-28 17:33:34 +02:00
Siddarth Kumar c1230319e1 nix: add fake git to status-go build derivation (#21989)
This commit adds a script that overrides `git` to echo version required by `status-go` derivation.

Also fixes error messages like this when building `status-go` :
```
fatal: not a git repository (or any of the parent directories): .git
```

These messages can be often misleading to some developers.
2025-01-27 18:14:27 +05:30
Lungu Cristian 1e48442d67 Fix dapps transactions instantly rejected (#21973)
* fix: upgraded status-go to fixed version

https://github.com/status-im/status-go/compare/4ec885a9...a2588ee5

* fix: use status-go develop branch

https://github.com/status-im/status-go/compare/4ec885a9...e71fdbc6

* build: using status-go v9.3.0

https://github.com/status-im/status-go/compare/4ec885a9...bec0c373
2025-01-27 13:20:40 +02:00
Sean Hagstrom 94fbbbcb3c fix: resolve UI glitches for chat, contacts, and keycard (#21946)
This change resolves some issues related to text-overflow in the app, and it also ensures we use the correct drawer title when editing a user nickname.
2025-01-24 15:51:46 +00:00
Yevheniia Berdnyk 4dfd616583 e2e: additional logging for errors in tests 2025-01-23 12:46:55 +02:00
Parvesh Monu 85d00e47af Keycard - Import a seed phrase into a new Keycard (#21947) 2025-01-23 12:23:33 +05:30
Ulises Manuel 438fd7a512 fix(chat): Same QR shown code for everyone in the Contacts tab (#21949) 2025-01-22 15:26:15 -06:00
Mohsen ee5f73f5ee [#21919] fix: remove on-ramp provider description and reinstate mecuryo (#21923)
* [#21919] fix: remove on-ramp provider description and reinstate mecuryo

https://github.com/status-im/status-go/compare/59caca61...07d07601

* [#21919] fix: rebase status-go

https://github.com/status-im/status-go/compare/4ec885a9...41743c6c
2025-01-22 17:59:08 +03:00
Volodymyr Kozieiev b49c0ae58a Fix local re-frisk launch (#21972) 2025-01-22 14:43:26 +00:00
68 changed files with 1643 additions and 773 deletions
+4 -2
View File
@@ -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;
+10 -6
View File
@@ -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"
+2 -1
View File
@@ -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}
+3 -2
View File
@@ -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
+1 -6
View File
@@ -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
+3 -3
View File
@@ -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
+9 -7
View File
@@ -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
[:=>
+1 -1
View File
@@ -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"))
+1 -6
View File
@@ -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])}]]]}))
+6 -2
View File
@@ -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
+25 -2
View File
@@ -3,16 +3,39 @@
[react-native.core :as rn]
[status-im.common.events-helper :as events-helper]
[status-im.common.resources :as resources]
[status-im.constants :as constants]
[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
@@ -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]]]})))
+21 -14
View File
@@ -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
[]
+13
View File
@@ -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)))))
+14 -8
View File
@@ -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))))}
@@ -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))))
+1 -1
View File
@@ -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]]
+7 -1
View File
@@ -64,6 +64,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]
@@ -1127,7 +1128,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)))
+5 -2
View File
@@ -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 -3
View File
@@ -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": "v9.3.0",
"commit-sha1": "bec0c3733eb9629153bc3df3d6294cec6a23af09",
"src-sha256": "0vj9vhmlf8csnpy8b0xiny425yzpl4wj1z873igb5av5hqllabf3"
}
@@ -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()
+6 -3
View File
@@ -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")
+50 -30
View File
@@ -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()
+316 -28
View File
@@ -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
@@ -20,6 +21,7 @@ class TestWalletMultipleDevice(MultipleSharedDeviceTestCase):
def prepare_devices(self):
self.network_api = NetworkApi()
print('1')
self.drivers, self.loop = create_shared_drivers(2)
self.sign_in_1, self.sign_in_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
self.sender, self.receiver = transaction_senders['ETH_1'], transaction_senders['ETH_2']
@@ -75,8 +77,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 +122,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 +146,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 +182,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 +212,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 +241,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 +258,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 +560,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 +580,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 +603,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 +622,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()
+4 -4
View File
@@ -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')
+12 -4
View File
@@ -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()
+63 -4
View File
@@ -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)
+5 -1
View File
@@ -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",
@@ -1227,6 +1227,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 +1349,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 +1383,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; youll 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",
@@ -2519,6 +2522,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",