Compare commits

..
Author SHA1 Message Date
pavloburykh 8427a4cc16 again some more fixing id700747 2022-03-30 15:54:29 +03:00
pavloburykh 6a31dc7aa7 some more fixing id700747 2022-03-30 15:28:44 +03:00
pavloburykh 214ce62d4d more fixing id700747 2022-03-30 15:15:53 +03:00
pavloburykh c24966d1a9 fixing id700747 2022-03-30 13:24:54 +03:00
pavloburykh d50324d8e6 fixing tests 700747 and 700759 2022-03-29 15:46:38 +03:00
pavloburykh 880858690a removed accidentaly added git line 2022-03-28 14:08:23 +03:00
pavloburykh 3f0435a374 changed common_password to qwerty1234 2022-03-28 14:02:48 +03:00
125 changed files with 8437 additions and 8962 deletions
-46
View File
@@ -1,49 +1,3 @@
## 1.19 Release notes
### Features
* 💬 Re-open app on the last open chat ([details](https://github.com/status-im/status-react/issues/12782))
* 🪙 Support \$UBI token ([details](https://github.com/status-im/status-react/issues/12975))
* 🔔 Implementation of remote android notifications ([details](https://github.com/status-im/status-react/issues/12866))
* 🔁 Sync clear history on paired devices ([details](https://github.com/status-im/status-react/issues/13004))
* 📑 Synchronize browser bookmarks/favorites across devices ([details](https://github.com/status-im/status-react/issues/12961))
* 🔕 Add mute option to android ([details](https://github.com/status-im/status-react/issues/12890))
* 👛 Wallet Connect 2.0 integration ([details](https://github.com/status-im/status-react/issues/12546))
* 💰 Implement Wallet Connect 1.0 ([details](https://github.com/status-im/status-react/issues/12870))
* ⚙️ Sync settings ([details](https://github.com/status-im/status-react/pull/13053))
### Improvements
* Improve order of mailserver requests ([details](https://github.com/status-im/status-react/issues/12783))
* Load images from an https server ([details](https://github.com/status-im/status-react/issues/12855))
* Load audio messages from https server ([details](https://github.com/status-im/status-react/issues/13116))
* Show message timestamps on tap, remove from bubbles 🕙 ([details](https://github.com/status-im/status-react/pull/12915))
* support PUK and seed recovery during onboarding ([details](https://github.com/status-im/status-react/pull/12955))
* update react-native-webview ([details](https://github.com/status-im/status-react/pull/12987))
* Add group members to mentionable list ([details](https://github.com/status-im/status-react/pull/12994))
* always use english for fallback text ([details](https://github.com/status-im/status-react/pull/13019))
* Disable chat input for chats with a blocked user ([details](https://github.com/status-im/status-react/pull/13162))
* Handle timeouts on mailserver requests ([details](https://github.com/status-im/status-react/issues/13022))
* Human Readable data display when signing using eth_signTypedData_v3 ([details](https://github.com/status-im/status-react/issues/12535))
### Bug Fixes
* Bug/fix opensea api ([details](https://github.com/status-im/status-react/pull/13021))
* Show "Fetch more messages" only in public chats and communities ([details](https://github.com/status-im/status-react/pull/12927))
* Chats are not synced if delete and re-add them on the first device while the second device is offline ([details](https://github.com/status-im/status-react/issues/12913))
* fix distortion of app theme due to change in system theme ([details](https://github.com/status-im/status-react/pull/12934))
* Unable to perform swap on 1inch.exchange if initial swap was cancelled by closing bottom sheet ([details](https://github.com/status-im/status-react/issues/12920))
* Error when trying to edit 'per-gas price limit' on 1inch.exchange ([details](https://github.com/status-im/status-react/issues/12991))
* Allow adding emoji in status input even if it exceeds limit ([details](https://github.com/status-im/status-react/pull/12949))
* Allow adding emoji to group intro message if it exceeds limit ([details](https://github.com/status-im/status-react/pull/13024))
* Use higher base fee value for default tx fee calculation ([details](https://github.com/status-im/status-react/pull/13020))
* Profile QR code overlaps share menu during sharing (IOS) ([details](https://github.com/status-im/status-react/pull/13050))
* No value in 'Gas amount limit' field in NFT dapps ([details](https://github.com/status-im/status-react/pull/13051))
* Stop showing fetch more button for cleared history ([details](https://github.com/status-im/status-react/pull/13084))
* fix ens resolve issue while following deep link ([details](https://github.com/status-im/status-react/pull/13080))
* Fix deadlock on syncing all data ([details](https://github.com/status-im/status-react/pull/13128))
* Fix broken username and timestamp layout for long usernames ([details](https://github.com/status-im/status-react/pull/13174))
## 1.18.0 Release notes :package:
### Features
+1 -4
View File
@@ -2,10 +2,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- These are added by React Native for debug mode, but actually aren't needed in release mode -->
<uses-permission tools:node="remove" android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<!-- Remove licensing permission since we don't license our app and it blocks F-Droid submissions. -->
<uses-permission tools:node="remove" android:name="com.android.vending.CHECK_LICENSE"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<application tools:targetApi="28" tools:ignore="GoogleAppIndexingWarning" android:usesCleartextTraffic="true" />
</manifest>
-2
View File
@@ -3,7 +3,5 @@
<!-- These are added by React Native for debug mode, but actually aren't needed in release mode -->
<uses-permission tools:node="remove" android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<!-- Remove licensing permission since we don't license our app and it blocks F-Droid submissions. -->
<uses-permission tools:node="remove" android:name="com.android.vending.CHECK_LICENSE"/>
</manifest>
+1 -3
View File
@@ -3,7 +3,5 @@
<!-- These are added by React Native for debug mode, but actually aren't needed in release mode -->
<uses-permission tools:node="remove" android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<!-- Remove licensing permission since we don't license our app and it blocks F-Droid submissions. -->
<uses-permission tools:node="remove" android:name="com.android.vending.CHECK_LICENSE"/>
</manifest>
</manifest>
+2 -2
View File
@@ -1,7 +1,7 @@
library 'status-jenkins-lib@v1.4.1'
library 'status-jenkins-lib@v1.3.5'
pipeline {
agent { label 'linux && x86_64 && nix-2.6' }
agent { label 'linux && x86_64 && nix-2.3' }
options {
timestamps()
+1 -1
View File
@@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.4.1'
library 'status-jenkins-lib@v1.3.5'
pipeline {
agent { label 'linux' }
+2 -2
View File
@@ -1,7 +1,7 @@
library 'status-jenkins-lib@v1.4.1'
library 'status-jenkins-lib@v1.3.5'
pipeline {
agent { label 'macos && x86_64 && nix-2.6 && xcode-12.5' }
agent { label 'macos && x86_64 && nix-2.3 && xcode-12.5' }
parameters {
string(
+1 -1
View File
@@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.4.1'
library 'status-jenkins-lib@v1.3.5'
pipeline {
agent { label params.AGENT_LABEL }
+3 -5
View File
@@ -1,5 +1,3 @@
library 'status-jenkins-lib@v1.4.1'
pipeline {
agent { label 'linux' }
@@ -14,7 +12,7 @@ pipeline {
string(
name: 'TEST_MARKERS',
description: 'Marker expression for matching tests to run.',
defaultValue: 'critical',
defaultValue: 'critical or high',
) */
string(
name: 'APK_NAME',
@@ -97,13 +95,13 @@ pipeline {
sh 'cp -f $TEST_ETH_ACCOUNTS_FILE users.py'
sh """
python3 -m pytest \
--numprocesses 9 \
--numprocesses 15 \
--rerun_count=2 \
--testrail_report=True \
-m \"${params.TEST_MARKERS}\" \
-k \"${params.KEYWORD_EXPRESSION}\" \
--apk=${params.APK_NAME} \
--build=PR-${params.PR_ID}-${utils.timestamp()} \
--build=PR-${params.PR_ID} \
--pr_number=${params.PR_ID} \
${extraPytestOpts}
"""
+1 -1
View File
@@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.4.1'
library 'status-jenkins-lib@v1.3.3'
pipeline {
agent { label 'macos' }
+1 -1
View File
@@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.4.1'
library 'status-jenkins-lib@v1.3.3'
pipeline {
agent { label 'linux' }
+34 -38
View File
@@ -1,30 +1,30 @@
GEM
remote: https://rubygems.org/
specs:
CFPropertyList (3.0.5)
CFPropertyList (3.0.4)
rexml
addressable (2.8.0)
public_suffix (>= 2.0.2, < 5.0)
artifactory (3.0.15)
atomos (0.1.3)
aws-eventstream (1.2.0)
aws-partitions (1.579.0)
aws-sdk-core (3.130.2)
aws-partitions (1.525.0)
aws-sdk-core (3.122.0)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.525.0)
aws-sigv4 (~> 1.1)
jmespath (~> 1.0)
aws-sdk-kms (1.56.0)
aws-sdk-core (~> 3, >= 3.127.0)
aws-sdk-kms (1.51.0)
aws-sdk-core (~> 3, >= 3.122.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.113.1)
aws-sdk-core (~> 3, >= 3.127.0)
aws-sdk-s3 (1.105.1)
aws-sdk-core (~> 3, >= 3.122.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4)
aws-sigv4 (1.5.0)
aws-sigv4 (1.4.0)
aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.4)
claide (1.1.0)
claide (1.0.3)
colored (1.2)
colored2 (3.1.2)
commander (4.6.0)
@@ -36,18 +36,17 @@ GEM
unf (>= 0.0.5, < 1.0.0)
dotenv (2.7.6)
emoji_regex (3.2.3)
excon (0.92.2)
faraday (1.10.0)
excon (0.88.0)
faraday (1.8.0)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1)
faraday-httpclient (~> 1.0)
faraday-multipart (~> 1.0)
faraday-httpclient (~> 1.0.1)
faraday-net_http (~> 1.0)
faraday-net_http_persistent (~> 1.0)
faraday-net_http_persistent (~> 1.1)
faraday-patron (~> 1.0)
faraday-rack (~> 1.0)
faraday-retry (~> 1.0)
multipart-post (>= 1.2, < 3)
ruby2_keywords (>= 0.0.4)
faraday-cookie_jar (0.0.7)
faraday (>= 0.8.0)
@@ -56,17 +55,14 @@ GEM
faraday-em_synchrony (1.0.0)
faraday-excon (1.1.0)
faraday-httpclient (1.0.1)
faraday-multipart (1.0.3)
multipart-post (>= 1.2, < 3)
faraday-net_http (1.0.1)
faraday-net_http_persistent (1.2.0)
faraday-patron (1.0.0)
faraday-rack (1.0.0)
faraday-retry (1.0.3)
faraday_middleware (1.2.0)
faraday (~> 1.0)
fastimage (2.2.6)
fastlane (2.205.2)
fastimage (2.2.5)
fastlane (2.197.0)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.8, < 3.0.0)
artifactory (~> 3.0)
@@ -109,9 +105,9 @@ GEM
fastlane-plugin-diawi (2.1.0)
rest-client (>= 2.0.0)
gh_inspector (1.1.3)
google-apis-androidpublisher_v3 (0.19.0)
google-apis-androidpublisher_v3 (0.13.0)
google-apis-core (>= 0.4, < 2.a)
google-apis-core (0.4.2)
google-apis-core (0.4.1)
addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.16.2, < 2.a)
httpclient (>= 2.8.1, < 3.a)
@@ -120,28 +116,28 @@ GEM
retriable (>= 2.0, < 4.a)
rexml
webrick
google-apis-iamcredentials_v1 (0.10.0)
google-apis-iamcredentials_v1 (0.8.0)
google-apis-core (>= 0.4, < 2.a)
google-apis-playcustomapp_v1 (0.7.0)
google-apis-playcustomapp_v1 (0.6.0)
google-apis-core (>= 0.4, < 2.a)
google-apis-storage_v1 (0.13.0)
google-apis-storage_v1 (0.9.0)
google-apis-core (>= 0.4, < 2.a)
google-cloud-core (1.6.0)
google-cloud-env (~> 1.0)
google-cloud-errors (~> 1.0)
google-cloud-env (1.6.0)
faraday (>= 0.17.3, < 3.0)
google-cloud-env (1.5.0)
faraday (>= 0.17.3, < 2.0)
google-cloud-errors (1.2.0)
google-cloud-storage (1.36.2)
addressable (~> 2.8)
google-cloud-storage (1.34.1)
addressable (~> 2.5)
digest-crc (~> 0.4)
google-apis-iamcredentials_v1 (~> 0.1)
google-apis-storage_v1 (~> 0.1)
google-cloud-core (~> 1.6)
googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0)
googleauth (1.1.3)
faraday (>= 0.17.3, < 3.a)
googleauth (1.1.0)
faraday (>= 0.17.3, < 2.0)
jwt (>= 1.4, < 3.0)
memoist (~> 0.16)
multi_json (~> 1.11)
@@ -152,13 +148,13 @@ GEM
http-cookie (1.0.4)
domain_name (~> 0.5)
httpclient (2.8.3)
jmespath (1.6.1)
jmespath (1.4.0)
json (2.6.1)
jwt (2.3.0)
memoist (0.16.2)
mime-types (3.4.1)
mime-types (3.3.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2022.0105)
mime-types-data (3.2021.0901)
mini_magick (4.11.0)
mini_mime (1.1.2)
multi_json (1.15.0)
@@ -169,7 +165,7 @@ GEM
optparse (0.1.1)
os (1.1.4)
plist (3.6.0)
public_suffix (4.0.7)
public_suffix (4.0.6)
rake (13.0.6)
representable (3.1.1)
declarative (< 0.1.0)
@@ -186,9 +182,9 @@ GEM
ruby2_keywords (0.0.5)
rubyzip (2.3.2)
security (0.1.3)
signet (0.16.1)
signet (0.16.0)
addressable (~> 2.8)
faraday (>= 0.17.5, < 3.0)
faraday (>= 0.17.3, < 2.0)
jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
simctl (1.6.8)
@@ -205,7 +201,7 @@ GEM
uber (0.1.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.8.1)
unf_ext (0.0.8)
unicode-display_width (1.8.0)
webrick (1.7.0)
word_wrap (1.0.0)
+51 -72
View File
@@ -45,10 +45,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1ilhspsph7icrrz94f3qngjkj585hsyv9bnxr44iabcqqwymr79w";
sha256 = "181a2xf9zs0hz77jkpmxidvkjzs65vsyqv1a31fcali7f0kvh4h9";
type = "gem";
};
version = "1.579.0";
version = "1.525.0";
};
aws-sdk-core = {
dependencies = ["aws-eventstream" "aws-partitions" "aws-sigv4" "jmespath"];
@@ -56,10 +56,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0hajbavfngn99hcz6n20162jygvwdflldvnlrza7z32hizawaaan";
sha256 = "0krx8cfajc72gv6mpyb67vnhd2m2iya19846jgipgfris194gjm2";
type = "gem";
};
version = "3.130.2";
version = "3.122.0";
};
aws-sdk-kms = {
dependencies = ["aws-sdk-core" "aws-sigv4"];
@@ -67,10 +67,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "14dcfqqdx1dy7qwrdyqdvqjs53kswm4njvg34f61jpl9xi3h2yf3";
sha256 = "0qac9dd6qriz6ldghkr8ga74zz28jl109kmvhvag74a3qf7k9dwj";
type = "gem";
};
version = "1.56.0";
version = "1.51.0";
};
aws-sdk-s3 = {
dependencies = ["aws-sdk-core" "aws-sdk-kms" "aws-sigv4"];
@@ -78,10 +78,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0kxcc3abjxld66ryrivfq9wxxpik8ngr2b2dr7shgrsgf5zmrkh8";
sha256 = "12j7i6l52b6hsnj59grn0m1s9pn6l38zmra6ad8i12vdsvd185w7";
type = "gem";
};
version = "1.113.1";
version = "1.105.1";
};
aws-sigv4 = {
dependencies = ["aws-eventstream"];
@@ -89,10 +89,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0xp7diwq7nv4vvxrl9x3lis2l4x6bissrfzbfyy6rv5bmj5w109z";
sha256 = "1wh1y79v0s4zgby2m79bnifk65hwf5pvk2yyrxzn2jkjjq8f8fqa";
type = "gem";
};
version = "1.5.0";
version = "1.4.0";
};
babosa = {
groups = ["default"];
@@ -110,20 +110,20 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "193l8r1ycd3dcxa7lsb4pqcghbk56dzc5244m6y8xmv88z6m31d7";
sha256 = "00s388z1akvj2j77ylr1mgp02zxp4ybcgc4ds3bz4647dfk0cwxk";
type = "gem";
};
version = "3.0.5";
version = "3.0.4";
};
claide = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0bpqhc0kqjp1bh9b7ffc395l9gfls0337rrhmab4v46ykl45qg3d";
sha256 = "0kasxsms24fgcdsq680nz99d5lazl9rmz1qkil2y5gbbssx89g0z";
type = "gem";
};
version = "1.1.0";
version = "1.0.3";
};
colored = {
groups = ["default"];
@@ -213,21 +213,21 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "01pcl1vx60x3f28rs6iw1lgqxycgb2yxq2p45k7b4a8liadykhba";
sha256 = "15yrwawhvkjvfg0dsf8z81876ddj6161q0wh5s7pw4sim8z8pspr";
type = "gem";
};
version = "0.92.2";
version = "0.88.0";
};
faraday = {
dependencies = ["faraday-em_http" "faraday-em_synchrony" "faraday-excon" "faraday-httpclient" "faraday-multipart" "faraday-net_http" "faraday-net_http_persistent" "faraday-patron" "faraday-rack" "faraday-retry" "ruby2_keywords"];
dependencies = ["faraday-em_http" "faraday-em_synchrony" "faraday-excon" "faraday-httpclient" "faraday-net_http" "faraday-net_http_persistent" "faraday-patron" "faraday-rack" "multipart-post" "ruby2_keywords"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "00palwawk897p5gypw5wjrh93d4p0xz2yl9w93yicb4kq7amh8d4";
sha256 = "0afhlqgby2cizcwgh7h2sq5f77q01axjbdl25bsvfwsry9n7gyyi";
type = "gem";
};
version = "1.10.0";
version = "1.8.0";
};
faraday-cookie_jar = {
dependencies = ["faraday" "http-cookie"];
@@ -280,17 +280,6 @@
};
version = "1.0.1";
};
faraday-multipart = {
dependencies = ["multipart-post"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "03qfi9020ynf7hkdiaq01sd2mllvw7fg4qiin3pk028b4wv23j3j";
type = "gem";
};
version = "1.0.3";
};
faraday-net_http = {
groups = ["default"];
platforms = [];
@@ -331,16 +320,6 @@
};
version = "1.0.0";
};
faraday-retry = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "153i967yrwnswqgvnnajgwp981k9p50ys1h80yz3q94rygs59ldd";
type = "gem";
};
version = "1.0.3";
};
faraday_middleware = {
dependencies = ["faraday"];
groups = ["default"];
@@ -357,10 +336,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0nnggg20za5vamdpkgrxxa32z33d8hf0g2bciswkhqnc6amb3yjr";
sha256 = "05i1fgqy4l40niwm9y56d04f876sm0cvc7q3w2rpddf8gya4lcs9";
type = "gem";
};
version = "2.2.6";
version = "2.2.5";
};
fastlane = {
dependencies = ["CFPropertyList" "addressable" "artifactory" "aws-sdk-s3" "babosa" "colored" "commander" "dotenv" "emoji_regex" "excon" "faraday" "faraday-cookie_jar" "faraday_middleware" "fastimage" "gh_inspector" "google-apis-androidpublisher_v3" "google-apis-playcustomapp_v1" "google-cloud-storage" "highline" "json" "jwt" "mini_magick" "multipart-post" "naturally" "optparse" "plist" "rubyzip" "security" "simctl" "terminal-notifier" "terminal-table" "tty-screen" "tty-spinner" "word_wrap" "xcodeproj" "xcpretty" "xcpretty-travis-formatter"];
@@ -368,10 +347,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "091l4vl909rv6alydwlzhbk0lfmfphb7n2sjybdfy2azr07b6a0d";
sha256 = "1qlvg0sca8j1ryzxpvnmpjnh3fwmv6sk8l7mr9mv34z8rdy1iv3x";
type = "gem";
};
version = "2.205.2";
version = "2.197.0";
};
fastlane-plugin-clean_testflight_testers = {
groups = ["default"];
@@ -410,10 +389,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0qc501qhgks10qr7dm42bjcsm6yrbg1lxy28akpxindvjk61zh9i";
sha256 = "1nxgda00y080xdavxs6nv5h2grwamds33b25nkjb4mij7385brs1";
type = "gem";
};
version = "0.19.0";
version = "0.13.0";
};
google-apis-core = {
dependencies = ["addressable" "googleauth" "httpclient" "mini_mime" "representable" "retriable" "rexml" "webrick"];
@@ -421,10 +400,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "19v15vkgg86k79l51gfs7fab4h7fkv8358ckmkyp33jgsx3zr17b";
sha256 = "1nzzj66clgr9ldmbjqkzgpvqmd6bjjmbw6khpgq80mp3gks4ycqy";
type = "gem";
};
version = "0.4.2";
version = "0.4.1";
};
google-apis-iamcredentials_v1 = {
dependencies = ["google-apis-core"];
@@ -432,10 +411,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1yibminaffzz5npq605m0vqc024dcybiw7xk5vr0jxzlsh8nxvhn";
sha256 = "0slpmdjsxbjdqs7qwkyfk3sdnfy5wliwf89jy8hq7l87a31r7lvk";
type = "gem";
};
version = "0.10.0";
version = "0.8.0";
};
google-apis-playcustomapp_v1 = {
dependencies = ["google-apis-core"];
@@ -443,10 +422,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "15wnkbn6kzijbyqkqrh7s6apjf5630yvf2v8zy93zk0x87n2drcd";
sha256 = "0v9y6avlnwxwv4vahhygrsmrpmric4zg8sxjd26vhhlxw6g8955b";
type = "gem";
};
version = "0.7.0";
version = "0.6.0";
};
google-apis-storage_v1 = {
dependencies = ["google-apis-core"];
@@ -454,10 +433,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0lcb9jkjipz1kgg8zyp8a6741andads55bxbldg3x8qmzkv9pv31";
sha256 = "0y6gyqj2cwsbdxk7wsrjzp9jz2hn2bk1zi1jjm5k311c3jlnj0r1";
type = "gem";
};
version = "0.13.0";
version = "0.9.0";
};
google-cloud-core = {
dependencies = ["google-cloud-env" "google-cloud-errors"];
@@ -476,10 +455,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "05gshdqscg4kil6ppfzmikyavsx449bxyj47j33r4n4p8swsqyb1";
sha256 = "0ajc3w4wqg46ywcbmb5fz1q6gfm6g7874s9h31i1r038kz2bzfag";
type = "gem";
};
version = "1.6.0";
version = "1.5.0";
};
google-cloud-errors = {
groups = ["default"];
@@ -497,10 +476,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "09d1bvxma4czbgay9lhcqsrhh6pd8s9i5djflzpsn00h4isdilw3";
sha256 = "1pvcpqx64cxm05dzr9q7zxrymjq4jk46ifd1p4b6c9v3v0c9ipb5";
type = "gem";
};
version = "1.36.2";
version = "1.34.1";
};
googleauth = {
dependencies = ["faraday" "jwt" "memoist" "multi_json" "os" "signet"];
@@ -508,10 +487,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1y80y72bpz04piiskfn93i5rzfy02mjchp3ym77yf2811gzz33d9";
sha256 = "12zm6r7jxqv8k1a4iyijq2gcywk2d62nizbnabwsnhnzxwxwxc3s";
type = "gem";
};
version = "1.1.3";
version = "1.1.0";
};
highline = {
groups = ["default"];
@@ -559,10 +538,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1mnvb80cdg7fzdcs3xscv21p28w4igk5sj5m7m81xp8v2ks87jj0";
sha256 = "1d4wac0dcd1jf6kc57891glih9w57552zgqswgy74d1xhgnk0ngf";
type = "gem";
};
version = "1.6.1";
version = "1.4.0";
};
json = {
groups = ["default"];
@@ -600,20 +579,20 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0ipw892jbksbxxcrlx9g5ljq60qx47pm24ywgfbyjskbcl78pkvb";
sha256 = "1zj12l9qk62anvk9bjvandpa6vy4xslil15wl6wlivyf51z773vh";
type = "gem";
};
version = "3.4.1";
version = "3.3.1";
};
mime-types-data = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "003gd7mcay800k2q4pb2zn8lwwgci4bhi42v2jvlidm8ksx03i6q";
sha256 = "1z5wvk6qi4ws1kjh7xn1rfirqw5m72bwvqacck1fjpbh33pcrwxv";
type = "gem";
};
version = "3.2022.0105";
version = "3.2021.0901";
};
mini_magick = {
groups = ["default"];
@@ -720,10 +699,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1f3knlwfwm05sfbaihrxm4g772b79032q14c16q4b38z8bi63qcb";
sha256 = "1xqcgkl7bwws1qrlnmxgh8g4g9m10vg60bhlw40fplninb3ng6d9";
type = "gem";
};
version = "4.0.7";
version = "4.0.6";
};
rake = {
groups = ["default"];
@@ -823,10 +802,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1jwyggz80xb3yi2hycmmw214c4072g8i56y0b0gsmpkiyk5d0vh1";
sha256 = "0cgmadrpgkpcklvvm2cga9mnrfqwqlydwpask1wx617h5ha6954k";
type = "gem";
};
version = "0.16.1";
version = "0.16.0";
};
simctl = {
dependencies = ["CFPropertyList" "naturally"];
@@ -927,10 +906,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0bf120xbq23zjyf8zi8h1576d71g58srr8rndig0whn10w72vrxz";
sha256 = "0jmbimpnpjdzz8hlrppgl9spm99qh3qzbx0b81k3gkgwba8nk3yd";
type = "gem";
};
version = "0.0.8.1";
version = "0.0.8";
};
unicode-display_width = {
groups = ["default"];
+11 -9
View File
@@ -2,7 +2,7 @@ PODS:
- boost-for-react-native (1.63.0)
- BVLinearGradient (2.5.6):
- React
- CryptoSwift (1.5.1)
- CryptoSwift (1.4.3)
- DoubleConversion (1.1.6)
- FBLazyVector (0.63.4)
- FBReactNativeSpec (0.63.4):
@@ -22,10 +22,9 @@ PODS:
- DoubleConversion
- glog
- glog (0.3.5)
- Keycard (3.0.5):
- Keycard (3.0.4):
- CryptoSwift
- secp256k1
- Zip
- libwebp (1.2.1):
- libwebp/demux (= 1.2.1)
- libwebp/mux (= 1.2.1)
@@ -306,6 +305,8 @@ PODS:
- React-jsi (= 0.63.4)
- ReactNativeAudioToolkit (2.0.3):
- React
- ReactNativeDarkMode (0.2.2):
- React
- ReactNativeNavigation (7.13.0):
- React-Core
- React-RCTImage
@@ -400,7 +401,6 @@ PODS:
- TouchID (4.4.1):
- React
- Yoga (1.14.0)
- Zip (2.1.2)
DEPENDENCIES:
- BVLinearGradient (from `../node_modules/react-native-linear-gradient`)
@@ -453,6 +453,7 @@ DEPENDENCIES:
- React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
- "ReactNativeAudioToolkit (from `../node_modules/@react-native-community/audio-toolkit`)"
- ReactNativeDarkMode (from `../node_modules/react-native-dark-mode`)
- ReactNativeNavigation (from `../node_modules/react-native-navigation`)
- "RNCAsyncStorage (from `../node_modules/@react-native-community/async-storage`)"
- "RNCClipboard (from `../node_modules/@react-native-community/clipboard`)"
@@ -486,7 +487,6 @@ SPEC REPOS:
- SQLCipher
- SSZipArchive
- TOCropViewController
- Zip
EXTERNAL SOURCES:
BVLinearGradient:
@@ -585,6 +585,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon"
ReactNativeAudioToolkit:
:path: "../node_modules/@react-native-community/audio-toolkit"
ReactNativeDarkMode:
:path: "../node_modules/react-native-dark-mode"
ReactNativeNavigation:
:path: "../node_modules/react-native-navigation"
RNCAsyncStorage:
@@ -629,7 +631,7 @@ EXTERNAL SOURCES:
CHECKOUT OPTIONS:
Keycard:
:commit: 29c26b51ef76304e9551657c605fb55b2540a077
:commit: d5bb5d68dbac19a34945918b51873fbba2c18310
:git: https://github.com/status-im/Keycard.swift.git
secp256k1:
:commit: 46a1fa30d9b8babeae85ff519050f42394ab5fcc
@@ -639,13 +641,13 @@ CHECKOUT OPTIONS:
SPEC CHECKSUMS:
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
BVLinearGradient: e3aad03778a456d77928f594a649e96995f1c872
CryptoSwift: c4f2debceb38bf44c80659afe009f71e23e4a082
CryptoSwift: a0799ee936271bd2253a006f1e4523df21845000
DoubleConversion: cde416483dac037923206447da6e1454df403714
FBLazyVector: 3bb422f41b18121b71783a905c10e58606f7dc3e
FBReactNativeSpec: f2c97f2529dd79c083355182cc158c9f98f4bd6e
Folly: b73c3869541e86821df3c387eb0af5f65addfab4
glog: 61334f8bdb4deea07543d4fbac3fb5948e78a7a5
Keycard: 07f1b4d4fadcf1218084cb3e1bb3a8bac3870c5a
Keycard: dd96182888da0aacf4de821b641103143bbb26cc
libwebp: 98a37e597e40bfdb4c911fc98f2c53d0b12d05fc
Permission-Camera: afad27bf90337684d4a86f3825112d648c8c4d3b
Permission-Microphone: 0ffabc3fe1c75cfb260525ee3f529383c9f4368c
@@ -688,6 +690,7 @@ SPEC CHECKSUMS:
React-RCTVibration: ae4f914cfe8de7d4de95ae1ea6cc8f6315d73d9d
ReactCommon: 73d79c7039f473b76db6ff7c6b159c478acbbb3b
ReactNativeAudioToolkit: de9610f323e855ac6574be8c99621f3d57c5df06
ReactNativeDarkMode: 0178ffca3b10f6a7c9f49d6f9810232b328fa949
ReactNativeNavigation: 4c4ca87edc0da4ee818158a62cb6188088454e5c
RNCAsyncStorage: d059c3ee71738c39834a627476322a5a8cd5bf36
RNCClipboard: 8148e21ac347c51fd6cd4b683389094c216bb543
@@ -713,7 +716,6 @@ SPEC CHECKSUMS:
TOCropViewController: edfd4f25713d56905ad1e0b9f5be3fbe0f59c863
TouchID: ba4c656d849cceabc2e4eef722dea5e55959ecf4
Yoga: 4bd86afe9883422a7c4028c00e34790f560923d6
Zip: b3fef584b147b6e582b2256a9815c897d60ddc67
PODFILE CHECKSUM: 1a5b8878f89edd08eb4d37898a3a8721a7bb3388
+120 -121
View File
@@ -35,20 +35,20 @@
3AAD2AD324A3A60E0075D594 /* Inter-SemiBold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 693A62DB37BC4CD5A30E5C96 /* Inter-SemiBold.otf */; };
3AAD2AD424A3A60E0075D594 /* Inter-SemiBoldItalic.otf in Resources */ = {isa = PBXBuildFile; fileRef = A4F2BBE8D4DD4140A6CCAC39 /* Inter-SemiBoldItalic.otf */; };
3ABC7AF8245FF85900612C45 /* InterStatus-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = 9C76AF5A418D4D65A4CAD1D9 /* InterStatus-Regular.otf */; };
41D83275EA021DE1470B64CB /* libPods-Status-StatusIm.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 46444D4C653CD27349ED6C7D /* libPods-Status-StatusIm.a */; };
57C854A7993C47A3B1AECD32 /* Inter-MediumItalic.otf in Resources */ = {isa = PBXBuildFile; fileRef = C6B1215047604CD59A4C74D6 /* Inter-MediumItalic.otf */; };
65F6941925780A4F00A45E76 /* Bridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F6941825780A4F00A45E76 /* Bridge.swift */; };
65F6941A25780A4F00A45E76 /* Bridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F6941825780A4F00A45E76 /* Bridge.swift */; };
65F6941B25780A4F00A45E76 /* Bridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F6941825780A4F00A45E76 /* Bridge.swift */; };
68E19BBDF749E72ED1F9DEF5 /* libPods-Status-StatusIm.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 132CE3B093884B0FB239A0AB /* libPods-Status-StatusIm.a */; };
6C137817D5298C82BC79177C /* libPods-Status-StatusImPR.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5D4CB5416994C913628B8754 /* libPods-Status-StatusImPR.a */; };
70ADBB5ECF934DCF8A0E4919 /* Inter-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = 1426DF592BA248FC81D955CB /* Inter-Regular.otf */; };
74B758FC20D7C00B003343C3 /* launch-image-universal.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 74B758FB20D7C00B003343C3 /* launch-image-universal.storyboard */; };
8391E8E0E93C41A98AAA6631 /* Inter-SemiBoldItalic.otf in Resources */ = {isa = PBXBuildFile; fileRef = A4F2BBE8D4DD4140A6CCAC39 /* Inter-SemiBoldItalic.otf */; };
A469E8D0A04F890FD80E5C08 /* libPods-Status-StatusImPR.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4364C6D4F636EFD8B968531E /* libPods-Status-StatusImPR.a */; };
8770D567D65A8F938D95C371 /* libPods-Status-StatusIm-StatusImTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DB52D45D10528E6992A83A71 /* libPods-Status-StatusIm-StatusImTests.a */; };
B24FC7FD1DE7195700D694FF /* Social.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B24FC7FC1DE7195700D694FF /* Social.framework */; };
B24FC7FF1DE7195F00D694FF /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B24FC7FE1DE7195F00D694FF /* MessageUI.framework */; };
B2F2D1BC1D9D531B00B7B453 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B2F2D1BB1D9D531B00B7B453 /* Images.xcassets */; };
BA68A2377A20496EA737000D /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 4E586E1B0E544F64AA9F5BD1 /* libz.tbd */; };
C6359065E518CA78EF03F567 /* libPods-Status-StatusIm-StatusImTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 10DE74ADA21099BC94EFD94D /* libPods-Status-StatusIm-StatusImTests.a */; };
CE4E31B31D8695250033ED64 /* Statusgo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE4E31B21D8695250033ED64 /* Statusgo.framework */; };
D1786306E0184916B11F4C37 /* Inter-Medium.otf in Resources */ = {isa = PBXBuildFile; fileRef = B2A38FC3D3954DE7B2B171F8 /* Inter-Medium.otf */; };
D84616FB563A48EBB1678699 /* Inter-Bold.otf in Resources */ = {isa = PBXBuildFile; fileRef = CD4A2C27D6D5473184DC1F7E /* Inter-Bold.otf */; };
@@ -96,38 +96,39 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
0032155E8656A85DCE5E0FBF /* Pods-Status-StatusImPR.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Status-StatusImPR.debug.xcconfig"; path = "Target Support Files/Pods-Status-StatusImPR/Pods-Status-StatusImPR.debug.xcconfig"; sourceTree = "<group>"; };
008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = "<group>"; };
00E356EE1AD99517003FC87E /* StatusImTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = StatusImTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
00E356F21AD99517003FC87E /* StatusImTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = StatusImTests.m; sourceTree = "<group>"; };
10DE74ADA21099BC94EFD94D /* libPods-Status-StatusIm-StatusImTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Status-StatusIm-StatusImTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
132CE3B093884B0FB239A0AB /* libPods-Status-StatusIm.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Status-StatusIm.a"; sourceTree = BUILT_PRODUCTS_DIR; };
13B07F961A680F5B00A75B9A /* StatusIm.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = StatusIm.app; sourceTree = BUILT_PRODUCTS_DIR; };
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = StatusIm/AppDelegate.h; sourceTree = "<group>"; };
13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = StatusIm/AppDelegate.m; sourceTree = "<group>"; };
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = StatusIm/Info.plist; sourceTree = "<group>"; };
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = StatusIm/main.m; sourceTree = "<group>"; };
1426DF592BA248FC81D955CB /* Inter-Regular.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Inter-Regular.otf"; path = "../resources/fonts/Inter-Regular.otf"; sourceTree = "<group>"; };
3887F5B027AC2EC4E7B8BC02 /* Pods-Status-StatusIm.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Status-StatusIm.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Status-StatusIm/Pods-Status-StatusIm.debug.xcconfig"; sourceTree = "<group>"; };
3A2626CE245C3F2200D5F94B /* Dummy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Dummy.swift; sourceTree = "<group>"; };
3A6406FB24A3ADF90046ED37 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
3A8F8EA924A4D31600BF206D /* GameKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameKit.framework; path = System/Library/Frameworks/GameKit.framework; sourceTree = SDKROOT; };
3AAD2ADC24A3A60E0075D594 /* Status PR.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Status PR.app"; sourceTree = BUILT_PRODUCTS_DIR; };
3AB1C3AD245C043900098F67 /* StatusIm-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "StatusIm-Bridging-Header.h"; sourceTree = "<group>"; };
42C2B8BE641784CC8F992EF6 /* Pods-Status-StatusIm.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Status-StatusIm.release.xcconfig"; path = "Target Support Files/Pods-Status-StatusIm/Pods-Status-StatusIm.release.xcconfig"; sourceTree = "<group>"; };
4364C6D4F636EFD8B968531E /* libPods-Status-StatusImPR.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Status-StatusImPR.a"; sourceTree = BUILT_PRODUCTS_DIR; };
46444D4C653CD27349ED6C7D /* libPods-Status-StatusIm.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Status-StatusIm.a"; sourceTree = BUILT_PRODUCTS_DIR; };
3F224519278D376B19F4CA2B /* Pods-Status-StatusIm-StatusImTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Status-StatusIm-StatusImTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-Status-StatusIm-StatusImTests/Pods-Status-StatusIm-StatusImTests.release.xcconfig"; sourceTree = "<group>"; };
4C16DE0B1F89508700AA10DB /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
4E586E1B0E544F64AA9F5BD1 /* libz.tbd */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
5D4CB5416994C913628B8754 /* libPods-Status-StatusImPR.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Status-StatusImPR.a"; sourceTree = BUILT_PRODUCTS_DIR; };
65F693BD2578002500A45E76 /* CoreNFC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreNFC.framework; path = System/Library/Frameworks/CoreNFC.framework; sourceTree = SDKROOT; };
65F693BF2578003600A45E76 /* CoreNFC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreNFC.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk/System/iOSSupport/System/Library/Frameworks/CoreNFC.framework; sourceTree = DEVELOPER_DIR; };
65F6941725780A4E00A45E76 /* StatusImTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "StatusImTests-Bridging-Header.h"; sourceTree = "<group>"; };
65F6941825780A4F00A45E76 /* Bridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bridge.swift; sourceTree = "<group>"; };
69291A6222A63434694EA2A6 /* Pods-Status-StatusImPR.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Status-StatusImPR.release.xcconfig"; path = "Pods/Target Support Files/Pods-Status-StatusImPR/Pods-Status-StatusImPR.release.xcconfig"; sourceTree = "<group>"; };
693A62DB37BC4CD5A30E5C96 /* Inter-SemiBold.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Inter-SemiBold.otf"; path = "../resources/fonts/Inter-SemiBold.otf"; sourceTree = "<group>"; };
74B758FB20D7C00B003343C3 /* launch-image-universal.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = "launch-image-universal.storyboard"; sourceTree = "<group>"; };
7D0115BCCB8330F6AC68CB87 /* Pods-Status-StatusIm.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Status-StatusIm.debug.xcconfig"; path = "Target Support Files/Pods-Status-StatusIm/Pods-Status-StatusIm.debug.xcconfig"; sourceTree = "<group>"; };
784390E981501E6517651C4E /* Pods-Status-StatusIm.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Status-StatusIm.release.xcconfig"; path = "Pods/Target Support Files/Pods-Status-StatusIm/Pods-Status-StatusIm.release.xcconfig"; sourceTree = "<group>"; };
7ACFEF4386C8FF7558A13B3D /* Pods-Status-StatusImPR.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Status-StatusImPR.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Status-StatusImPR/Pods-Status-StatusImPR.debug.xcconfig"; sourceTree = "<group>"; };
8B9A886A2CB448B1ABA0EB62 /* libc++.tbd */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; };
922C4CA61F4D5F8B0033C753 /* StatusIm.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = StatusIm.entitlements; path = StatusIm/StatusIm.entitlements; sourceTree = "<group>"; };
956436931E0887CF912BCC24 /* Pods-Status-StatusImPR.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Status-StatusImPR.release.xcconfig"; path = "Target Support Files/Pods-Status-StatusImPR/Pods-Status-StatusImPR.release.xcconfig"; sourceTree = "<group>"; };
977B1E37198B72A48870BFE5 /* Pods-Status-StatusIm-StatusImTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Status-StatusIm-StatusImTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Status-StatusIm-StatusImTests/Pods-Status-StatusIm-StatusImTests.debug.xcconfig"; sourceTree = "<group>"; };
9C76AF5A418D4D65A4CAD1D9 /* InterStatus-Regular.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "InterStatus-Regular.otf"; path = "../resources/fonts/InterStatus-Regular.otf"; sourceTree = "<group>"; };
9EC0135C1E06FB1900155B5C /* RCTWKWebView.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWKWebView.xcodeproj; path = "../node_modules/react-native-wkwebview-reborn/ios/RCTWKWebView.xcodeproj"; sourceTree = "<group>"; };
A4F2BBE8D4DD4140A6CCAC39 /* Inter-SemiBoldItalic.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Inter-SemiBoldItalic.otf"; path = "../resources/fonts/Inter-SemiBoldItalic.otf"; sourceTree = "<group>"; };
@@ -140,8 +141,7 @@
C6B1215047604CD59A4C74D6 /* Inter-MediumItalic.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Inter-MediumItalic.otf"; path = "../resources/fonts/Inter-MediumItalic.otf"; sourceTree = "<group>"; };
CD4A2C27D6D5473184DC1F7E /* Inter-Bold.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Inter-Bold.otf"; path = "../resources/fonts/Inter-Bold.otf"; sourceTree = "<group>"; };
CE4E31B21D8695250033ED64 /* Statusgo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Statusgo.framework; path = "../modules/react-native-status/ios/RCTStatus/Statusgo.framework"; sourceTree = "<group>"; };
E7378B0A7AE6C80DCC3C45BA /* Pods-Status-StatusIm-StatusImTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Status-StatusIm-StatusImTests.debug.xcconfig"; path = "Target Support Files/Pods-Status-StatusIm-StatusImTests/Pods-Status-StatusIm-StatusImTests.debug.xcconfig"; sourceTree = "<group>"; };
F1D775582F9C7154A44F2520 /* Pods-Status-StatusIm-StatusImTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Status-StatusIm-StatusImTests.release.xcconfig"; path = "Target Support Files/Pods-Status-StatusIm-StatusImTests/Pods-Status-StatusIm-StatusImTests.release.xcconfig"; sourceTree = "<group>"; };
DB52D45D10528E6992A83A71 /* libPods-Status-StatusIm-StatusImTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Status-StatusIm-StatusImTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -149,7 +149,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
C6359065E518CA78EF03F567 /* libPods-Status-StatusIm-StatusImTests.a in Frameworks */,
8770D567D65A8F938D95C371 /* libPods-Status-StatusIm-StatusImTests.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -162,7 +162,7 @@
CE4E31B31D8695250033ED64 /* Statusgo.framework in Frameworks */,
25DC9C9DC25846BD8D084888 /* libc++.tbd in Frameworks */,
BA68A2377A20496EA737000D /* libz.tbd in Frameworks */,
41D83275EA021DE1470B64CB /* libPods-Status-StatusIm.a in Frameworks */,
68E19BBDF749E72ED1F9DEF5 /* libPods-Status-StatusIm.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -176,7 +176,7 @@
3AAD2AC224A3A60E0075D594 /* Statusgo.framework in Frameworks */,
3AAD2AC524A3A60E0075D594 /* libc++.tbd in Frameworks */,
3AAD2AC624A3A60E0075D594 /* libz.tbd in Frameworks */,
A469E8D0A04F890FD80E5C08 /* libPods-Status-StatusImPR.a in Frameworks */,
6C137817D5298C82BC79177C /* libPods-Status-StatusImPR.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -233,20 +233,6 @@
name = Resources;
sourceTree = "<group>";
};
37F45ABDF8B0A9F2EF379D4B /* Pods */ = {
isa = PBXGroup;
children = (
7D0115BCCB8330F6AC68CB87 /* Pods-Status-StatusIm.debug.xcconfig */,
42C2B8BE641784CC8F992EF6 /* Pods-Status-StatusIm.release.xcconfig */,
E7378B0A7AE6C80DCC3C45BA /* Pods-Status-StatusIm-StatusImTests.debug.xcconfig */,
F1D775582F9C7154A44F2520 /* Pods-Status-StatusIm-StatusImTests.release.xcconfig */,
0032155E8656A85DCE5E0FBF /* Pods-Status-StatusImPR.debug.xcconfig */,
956436931E0887CF912BCC24 /* Pods-Status-StatusImPR.release.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
3AAD2AB624A3A5F10075D594 /* StatusImPR */ = {
isa = PBXGroup;
children = (
@@ -255,6 +241,19 @@
path = StatusImPR;
sourceTree = "<group>";
};
5C1C8762251D6EF495FB2384 /* Pods */ = {
isa = PBXGroup;
children = (
3887F5B027AC2EC4E7B8BC02 /* Pods-Status-StatusIm.debug.xcconfig */,
784390E981501E6517651C4E /* Pods-Status-StatusIm.release.xcconfig */,
977B1E37198B72A48870BFE5 /* Pods-Status-StatusIm-StatusImTests.debug.xcconfig */,
3F224519278D376B19F4CA2B /* Pods-Status-StatusIm-StatusImTests.release.xcconfig */,
7ACFEF4386C8FF7558A13B3D /* Pods-Status-StatusImPR.debug.xcconfig */,
69291A6222A63434694EA2A6 /* Pods-Status-StatusImPR.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
};
832341AE1AAA6A7D00B99B32 /* Libraries */ = {
isa = PBXGroup;
children = (
@@ -274,8 +273,8 @@
83CBBA001A601CBA00E9B192 /* Products */,
A97BA941B2FB44B4B66EE6D3 /* Frameworks */,
1E7837547A9A40E18AD63CF3 /* Resources */,
5C1C8762251D6EF495FB2384 /* Pods */,
65F6941725780A4E00A45E76 /* StatusImTests-Bridging-Header.h */,
37F45ABDF8B0A9F2EF379D4B /* Pods */,
);
indentWidth = 2;
sourceTree = "<group>";
@@ -312,9 +311,9 @@
CE4E31B21D8695250033ED64 /* Statusgo.framework */,
8B9A886A2CB448B1ABA0EB62 /* libc++.tbd */,
4E586E1B0E544F64AA9F5BD1 /* libz.tbd */,
46444D4C653CD27349ED6C7D /* libPods-Status-StatusIm.a */,
10DE74ADA21099BC94EFD94D /* libPods-Status-StatusIm-StatusImTests.a */,
4364C6D4F636EFD8B968531E /* libPods-Status-StatusImPR.a */,
132CE3B093884B0FB239A0AB /* libPods-Status-StatusIm.a */,
DB52D45D10528E6992A83A71 /* libPods-Status-StatusIm-StatusImTests.a */,
5D4CB5416994C913628B8754 /* libPods-Status-StatusImPR.a */,
);
name = Frameworks;
sourceTree = "<group>";
@@ -326,11 +325,11 @@
isa = PBXNativeTarget;
buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "StatusImTests" */;
buildPhases = (
E8158908D8DBE8B42209130F /* [CP] Check Pods Manifest.lock */,
49A69B853BD9751F84878340 /* [CP] Check Pods Manifest.lock */,
00E356EA1AD99517003FC87E /* Sources */,
00E356EB1AD99517003FC87E /* Frameworks */,
00E356EC1AD99517003FC87E /* Resources */,
814AF5E700528A517FFCE669 /* [CP] Copy Pods Resources */,
AFAB37B70B6EB1B7D2E869AD /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -346,14 +345,14 @@
isa = PBXNativeTarget;
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "StatusIm" */;
buildPhases = (
ADD15A0C44EC35A40730E491 /* [CP] Check Pods Manifest.lock */,
2EAC54E16AB243C3EBBFE1BA /* [CP] Check Pods Manifest.lock */,
13B07F871A680F5B00A75B9A /* Sources */,
13B07F8C1A680F5B00A75B9A /* Frameworks */,
13B07F8E1A680F5B00A75B9A /* Resources */,
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
20B6B6891D92C42700CC5C6A /* Embed Frameworks */,
E3914A731DF919ED00EBB515 /* Run Script */,
C25D61BD03A6CB56513896A5 /* [CP] Copy Pods Resources */,
291E1A8BC076990A77B59232 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -368,14 +367,14 @@
isa = PBXNativeTarget;
buildConfigurationList = 3AAD2AD924A3A60E0075D594 /* Build configuration list for PBXNativeTarget "StatusImPR" */;
buildPhases = (
78A12FD1CDEF079CF7CF7319 /* [CP] Check Pods Manifest.lock */,
3AAD2ABA24A3A60E0075D594 /* [CP] Check Pods Manifest.lock */,
3AAD2ABB24A3A60E0075D594 /* Sources */,
3AAD2ABF24A3A60E0075D594 /* Frameworks */,
3AAD2AC924A3A60E0075D594 /* Resources */,
3AAD2AD524A3A60E0075D594 /* Bundle React Native code and images */,
3AAD2AD624A3A60E0075D594 /* Embed Frameworks */,
3AAD2AD724A3A60E0075D594 /* Run Script */,
71AF560830EB55C8909CC37C /* [CP] Copy Pods Resources */,
3AAD2AD824A3A60E0075D594 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -523,6 +522,72 @@
shellPath = /bin/sh;
shellScript = "set -o errexit\nexport NODE_BINARY=\"node\"\nexport NODE_ARGS=\" --max-old-space-size=16384 \"\n\nbash -x ../node_modules/react-native/scripts/react-native-xcode.sh > ./react-native-xcode.log 2>&1";
};
291E1A8BC076990A77B59232 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Status-StatusIm/Pods-Status-StatusIm-resources.sh",
"${PODS_CONFIGURATION_BUILD_DIR}/RNImageCropPicker/QBImagePicker.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/TOCropViewController/TOCropViewControllerBundle.bundle",
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/QBImagePicker.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/TOCropViewControllerBundle.bundle",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Status-StatusIm/Pods-Status-StatusIm-resources.sh\"\n";
showEnvVarsInLog = 0;
};
2EAC54E16AB243C3EBBFE1BA /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Status-StatusIm-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
3AAD2ABA24A3A60E0075D594 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Status-StatusImPR-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
3AAD2AD524A3A60E0075D594 /* Bundle React Native code and images */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@@ -551,7 +616,7 @@
shellPath = /bin/sh;
shellScript = "\"${PROJECT_DIR}/scripts/set_xcode_version.sh\" > ./set_xcode_version.log 2>&1";
};
71AF560830EB55C8909CC37C /* [CP] Copy Pods Resources */ = {
3AAD2AD824A3A60E0075D594 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -573,7 +638,7 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Status-StatusImPR/Pods-Status-StatusImPR-resources.sh\"\n";
showEnvVarsInLog = 0;
};
78A12FD1CDEF079CF7CF7319 /* [CP] Check Pods Manifest.lock */ = {
49A69B853BD9751F84878340 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -588,14 +653,14 @@
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Status-StatusImPR-checkManifestLockResult.txt",
"$(DERIVED_FILE_DIR)/Pods-Status-StatusIm-StatusImTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
814AF5E700528A517FFCE669 /* [CP] Copy Pods Resources */ = {
AFAB37B70B6EB1B7D2E869AD /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -617,50 +682,6 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Status-StatusIm-StatusImTests/Pods-Status-StatusIm-StatusImTests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
ADD15A0C44EC35A40730E491 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Status-StatusIm-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
C25D61BD03A6CB56513896A5 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Status-StatusIm/Pods-Status-StatusIm-resources.sh",
"${PODS_CONFIGURATION_BUILD_DIR}/RNImageCropPicker/QBImagePicker.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/TOCropViewController/TOCropViewControllerBundle.bundle",
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/QBImagePicker.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/TOCropViewControllerBundle.bundle",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Status-StatusIm/Pods-Status-StatusIm-resources.sh\"\n";
showEnvVarsInLog = 0;
};
E3914A731DF919ED00EBB515 /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 8;
@@ -675,28 +696,6 @@
shellPath = /bin/sh;
shellScript = "\"${PROJECT_DIR}/scripts/set_xcode_version.sh\" > ./set_xcode_version.log 2>&1";
};
E8158908D8DBE8B42209130F /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Status-StatusIm-StatusImTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@@ -744,7 +743,7 @@
/* Begin XCBuildConfiguration section */
00E356F61AD99517003FC87E /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = E7378B0A7AE6C80DCC3C45BA /* Pods-Status-StatusIm-StatusImTests.debug.xcconfig */;
baseConfigurationReference = 977B1E37198B72A48870BFE5 /* Pods-Status-StatusIm-StatusImTests.debug.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_ID_SUFFIX = .debug;
@@ -777,7 +776,7 @@
};
00E356F71AD99517003FC87E /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = F1D775582F9C7154A44F2520 /* Pods-Status-StatusIm-StatusImTests.release.xcconfig */;
baseConfigurationReference = 3F224519278D376B19F4CA2B /* Pods-Status-StatusIm-StatusImTests.release.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_ID_SUFFIX = "";
@@ -806,7 +805,7 @@
};
13B07F941A680F5B00A75B9A /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7D0115BCCB8330F6AC68CB87 /* Pods-Status-StatusIm.debug.xcconfig */;
baseConfigurationReference = 3887F5B027AC2EC4E7B8BC02 /* Pods-Status-StatusIm.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon$(BUNDLE_ID_SUFFIX)";
BUNDLE_ID_SUFFIX = .debug;
@@ -876,7 +875,7 @@
};
13B07F951A680F5B00A75B9A /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 42C2B8BE641784CC8F992EF6 /* Pods-Status-StatusIm.release.xcconfig */;
baseConfigurationReference = 784390E981501E6517651C4E /* Pods-Status-StatusIm.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon$(BUNDLE_ID_SUFFIX)";
BUNDLE_ID_SUFFIX = "";
@@ -930,13 +929,13 @@
SWIFT_OBJC_BRIDGING_HEADER = "StatusIm-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
VALID_ARCHS = arm64;
VALID_ARCHS = "arm64";
};
name = Release;
};
3AAD2ADA24A3A60E0075D594 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 0032155E8656A85DCE5E0FBF /* Pods-Status-StatusImPR.debug.xcconfig */;
baseConfigurationReference = 7ACFEF4386C8FF7558A13B3D /* Pods-Status-StatusImPR.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon$(BUNDLE_ID_SUFFIX)";
BUNDLE_ID_SUFFIX = .debug;
@@ -995,13 +994,13 @@
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
VALID_ARCHS = arm64;
VALID_ARCHS = "arm64";
};
name = Debug;
};
3AAD2ADB24A3A60E0075D594 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 956436931E0887CF912BCC24 /* Pods-Status-StatusImPR.release.xcconfig */;
baseConfigurationReference = 69291A6222A63434694EA2A6 /* Pods-Status-StatusImPR.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = "AppIconPR$(BUNDLE_ID_SUFFIX)";
BUNDLE_ID_SUFFIX = "";
@@ -1053,7 +1052,7 @@
SWIFT_OBJC_BRIDGING_HEADER = "StatusIm-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
VALID_ARCHS = arm64;
VALID_ARCHS = "arm64";
};
name = Release;
};
@@ -1135,8 +1134,8 @@
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = NO;
SDKROOT = iphoneos;
VALID_ARCHS = arm64;
"VALID_ARCHS[sdk=iphonesimulator*]" = x86_64;
VALID_ARCHS = "arm64";
"VALID_ARCHS[sdk=iphonesimulator*]" = "x86_64";
};
name = Debug;
};
@@ -1209,7 +1208,7 @@
ONLY_ACTIVE_ARCH = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
VALID_ARCHS = arm64;
VALID_ARCHS = "arm64";
};
name = Release;
};
+25 -31
View File
@@ -1,33 +1,35 @@
# Known Issues
## Too many open files
## MacOS 10.15 "Catalina"
### Single-User Installation
There is an unsolved issue with the root(`/`) file system in `10.15` being read-only:
https://github.com/NixOS/nix/issues/2925
Nix can open a lot of files when fetching things for `/nix/store` which can cause
```
Too many open files"
```
The temporary way to fix this is set a new limit for current session using `ulimit`:
```sh
ulimit -n 131072
```
To increase limit permanently system-wide edit `/etc/sysctl.conf`:
```
fs.file-max = 131072
```
And use `sudo sysctl --system` to load these new settings.
Our current recommended workaround is putting `/nix` under `/opt/nix` and symlinking it via `/etc/synthetic.conf`:
### Multi-User Installation
The other reason why this error could appear are limits fo `nix-daemon` service:
https://github.com/NixOS/nix/issues/6007
Since Systemd services ignore system-wide limits you will have to add the following line:
```bash
sudo mkdir /opt/nix
sudo chown ${USER} /opt/nix
sudo sh -c "echo 'nix\t/opt/nix' >> /etc/synthetic.conf"
reboot
```
LimitNOFILE=4096:1048576
After the system reboots you should see the `/nix` symlink in place:
```bash
% ls -l /nix
lrwxr-xr-x 1 root wheel 8 Oct 11 13:53 /nix -> /opt/nix
```
To the `/etc/systemd/system/nix-daemon.service` service definition.
In order to be able to use Nix with a symlinked `/nix` you need to include this in your shell:
```bash
export NIX_IGNORE_SYMLINK_STORE=1
```
Add it to your `.bashrc` or any other shell config file.
__NOTE__: Your old `/nix` directory will end up in `/Users/Shared/Relocated Items/Security/nix` after OS upgrade.
## Cache Downloads Timing Out
@@ -67,11 +69,3 @@ Currently on NixOS `NIX_CONF_DIR` is being ignored in favor of the default `/etc
This will be possible to fix once Nix `2.4` comes out with support for `NIX_USER_CONF_FILES`.
For more details see https://github.com/NixOS/nix/issues/3723.
## Extra Sandbox Files Not Available
It's possible that on a multi-user installation files provided to the build sandbox using the `extra-sandbox-paths` option will ne be available, unless the current user is added to `trusted-users` in `nix.conf` file.
Issues:
* https://github.com/NixOS/nix/issues/6115
* https://github.com/NixOS/nix/issues/6217
+306 -386
View File
File diff suppressed because it is too large Load Diff
+61 -67
View File
@@ -323,7 +323,6 @@ https://plugins.gradle.org/m2/com/facebook/fresco/memory-type-java/2.2.0/memory-
https://plugins.gradle.org/m2/com/facebook/fresco/memory-type-native/2.2.0/memory-type-native-2.2.0.pom
https://plugins.gradle.org/m2/com/facebook/fresco/nativeimagefilters/2.2.0/nativeimagefilters-2.2.0.pom
https://plugins.gradle.org/m2/com/facebook/fresco/stetho/2.2.0/stetho-2.2.0.pom
https://repo.maven.apache.org/maven2/antlr/antlr/2.7.1/antlr-2.7.1.pom
https://repo.maven.apache.org/maven2/antlr/antlr/2.7.7/antlr-2.7.7.pom
https://repo.maven.apache.org/maven2/aopalliance/aopalliance/1.0/aopalliance-1.0.pom
https://repo.maven.apache.org/maven2/backport-util-concurrent/backport-util-concurrent/3.1/backport-util-concurrent-3.1.pom
@@ -475,12 +474,12 @@ https://repo.maven.apache.org/maven2/com/google/errorprone/error_prone_annotatio
https://repo.maven.apache.org/maven2/com/google/errorprone/error_prone_annotations/2.1.2/error_prone_annotations-2.1.2.pom
https://repo.maven.apache.org/maven2/com/google/errorprone/error_prone_annotations/2.2.0/error_prone_annotations-2.2.0.pom
https://repo.maven.apache.org/maven2/com/google/errorprone/error_prone_annotations/2.3.1/error_prone_annotations-2.3.1.pom
https://repo.maven.apache.org/maven2/com/google/errorprone/error_prone_annotations/2.13.1/error_prone_annotations-2.13.1.pom
https://repo.maven.apache.org/maven2/com/google/errorprone/error_prone_annotations/2.11.0/error_prone_annotations-2.11.0.pom
https://repo.maven.apache.org/maven2/com/google/errorprone/error_prone_parent/2.0.18/error_prone_parent-2.0.18.pom
https://repo.maven.apache.org/maven2/com/google/errorprone/error_prone_parent/2.1.2/error_prone_parent-2.1.2.pom
https://repo.maven.apache.org/maven2/com/google/errorprone/error_prone_parent/2.2.0/error_prone_parent-2.2.0.pom
https://repo.maven.apache.org/maven2/com/google/errorprone/error_prone_parent/2.3.1/error_prone_parent-2.3.1.pom
https://repo.maven.apache.org/maven2/com/google/errorprone/error_prone_parent/2.13.1/error_prone_parent-2.13.1.pom
https://repo.maven.apache.org/maven2/com/google/errorprone/error_prone_parent/2.11.0/error_prone_parent-2.11.0.pom
https://repo.maven.apache.org/maven2/com/google/google/1/google-1.pom
https://repo.maven.apache.org/maven2/com/google/google/5/google-5.pom
https://repo.maven.apache.org/maven2/com/google/guava/failureaccess/1.0.1/failureaccess-1.0.1.pom
@@ -490,14 +489,14 @@ https://repo.maven.apache.org/maven2/com/google/guava/guava-parent/23.0/guava-pa
https://repo.maven.apache.org/maven2/com/google/guava/guava-parent/26.0-android/guava-parent-26.0-android.pom
https://repo.maven.apache.org/maven2/com/google/guava/guava-parent/26.0-jre/guava-parent-26.0-jre.pom
https://repo.maven.apache.org/maven2/com/google/guava/guava-parent/27.0.1-jre/guava-parent-27.0.1-jre.pom
https://repo.maven.apache.org/maven2/com/google/guava/guava-parent/31.1-jre/guava-parent-31.1-jre.pom
https://repo.maven.apache.org/maven2/com/google/guava/guava-testlib/31.1-jre/guava-testlib-31.1-jre.pom
https://repo.maven.apache.org/maven2/com/google/guava/guava-parent/31.0.1-jre/guava-parent-31.0.1-jre.pom
https://repo.maven.apache.org/maven2/com/google/guava/guava-testlib/31.0.1-jre/guava-testlib-31.0.1-jre.pom
https://repo.maven.apache.org/maven2/com/google/guava/guava/17.0/guava-17.0.pom
https://repo.maven.apache.org/maven2/com/google/guava/guava/22.0/guava-22.0.pom
https://repo.maven.apache.org/maven2/com/google/guava/guava/23.0/guava-23.0.pom
https://repo.maven.apache.org/maven2/com/google/guava/guava/26.0-jre/guava-26.0-jre.pom
https://repo.maven.apache.org/maven2/com/google/guava/guava/27.0.1-jre/guava-27.0.1-jre.pom
https://repo.maven.apache.org/maven2/com/google/guava/guava/31.1-jre/guava-31.1-jre.pom
https://repo.maven.apache.org/maven2/com/google/guava/guava/31.0.1-jre/guava-31.0.1-jre.pom
https://repo.maven.apache.org/maven2/com/google/guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.pom
https://repo.maven.apache.org/maven2/com/google/inject/guice-parent/5.1.0/guice-parent-5.1.0.pom
https://repo.maven.apache.org/maven2/com/google/inject/guice/5.1.0/guice-5.1.0.pom
@@ -531,31 +530,32 @@ https://repo.maven.apache.org/maven2/com/squareup/okhttp3/okhttp-urlconnection/3
https://repo.maven.apache.org/maven2/com/squareup/okhttp3/okhttp/3.9.1/okhttp-3.9.1.pom
https://repo.maven.apache.org/maven2/com/squareup/okhttp3/okhttp/3.12.1/okhttp-3.12.1.pom
https://repo.maven.apache.org/maven2/com/squareup/okhttp3/okhttp/3.12.12/okhttp-3.12.12.pom
https://repo.maven.apache.org/maven2/com/squareup/okhttp3/okhttp/5.0.0-alpha.6/okhttp-5.0.0-alpha.6.pom
https://repo.maven.apache.org/maven2/com/squareup/okhttp3/okhttp/5.0.0-alpha.5/okhttp-5.0.0-alpha.5.pom
https://repo.maven.apache.org/maven2/com/squareup/okhttp3/parent/3.9.1/parent-3.9.1.pom
https://repo.maven.apache.org/maven2/com/squareup/okhttp3/parent/3.12.1/parent-3.12.1.pom
https://repo.maven.apache.org/maven2/com/squareup/okhttp3/parent/3.12.12/parent-3.12.12.pom
https://repo.maven.apache.org/maven2/com/squareup/okio/okio-parent/1.15.0/okio-parent-1.15.0.pom
https://repo.maven.apache.org/maven2/com/squareup/okio/okio/1.15.0/okio-1.15.0.pom
https://repo.maven.apache.org/maven2/com/squareup/okio/okio/3.0.0/okio-3.0.0.pom
https://repo.maven.apache.org/maven2/com/squareup/okio/okio/3.1.0/okio-3.1.0.pom
https://repo.maven.apache.org/maven2/com/sun/activation/all/1.2.0/all-1.2.0.pom
https://repo.maven.apache.org/maven2/com/sun/activation/all/2.0.1/all-2.0.1.pom
https://repo.maven.apache.org/maven2/com/sun/activation/jakarta.activation/2.0.1/jakarta.activation-2.0.1.pom
https://repo.maven.apache.org/maven2/com/sun/activation/javax.activation/1.2.0/javax.activation-1.2.0.pom
https://repo.maven.apache.org/maven2/com/sun/istack/istack-commons-runtime/2.21/istack-commons-runtime-2.21.pom
https://repo.maven.apache.org/maven2/com/sun/istack/istack-commons-runtime/4.1.1/istack-commons-runtime-4.1.1.pom
https://repo.maven.apache.org/maven2/com/sun/istack/istack-commons-runtime/4.1.0-M1/istack-commons-runtime-4.1.0-M1.pom
https://repo.maven.apache.org/maven2/com/sun/istack/istack-commons/2.21/istack-commons-2.21.pom
https://repo.maven.apache.org/maven2/com/sun/istack/istack-commons/4.1.1/istack-commons-4.1.1.pom
https://repo.maven.apache.org/maven2/com/sun/istack/istack-commons/4.1.0-M1/istack-commons-4.1.0-M1.pom
https://repo.maven.apache.org/maven2/com/sun/xml/bind/jaxb-bom-ext/2.2.11/jaxb-bom-ext-2.2.11.pom
https://repo.maven.apache.org/maven2/com/sun/xml/bind/jaxb-bom-ext/4.0.0-M4/jaxb-bom-ext-4.0.0-M4.pom
https://repo.maven.apache.org/maven2/com/sun/xml/bind/jaxb-bom-ext/3.0.2/jaxb-bom-ext-3.0.2.pom
https://repo.maven.apache.org/maven2/com/sun/xml/bind/mvn/jaxb-parent/2.2.11/jaxb-parent-2.2.11.pom
https://repo.maven.apache.org/maven2/com/sun/xml/bind/mvn/jaxb-parent/4.0.0-M4/jaxb-parent-4.0.0-M4.pom
https://repo.maven.apache.org/maven2/com/sun/xml/bind/mvn/jaxb-parent/3.0.2/jaxb-parent-3.0.2.pom
https://repo.maven.apache.org/maven2/com/sun/xml/bind/mvn/jaxb-runtime-parent/2.2.11/jaxb-runtime-parent-2.2.11.pom
https://repo.maven.apache.org/maven2/com/sun/xml/bind/mvn/jaxb-txw-parent/2.2.11/jaxb-txw-parent-2.2.11.pom
https://repo.maven.apache.org/maven2/com/sun/xml/bind/mvn/jaxb-txw-parent/4.0.0-M4/jaxb-txw-parent-4.0.0-M4.pom
https://repo.maven.apache.org/maven2/com/sun/xml/bind/mvn/jaxb-txw-parent/3.0.2/jaxb-txw-parent-3.0.2.pom
https://repo.maven.apache.org/maven2/com/sun/xml/fastinfoset/FastInfoset/1.2.13/FastInfoset-1.2.13.pom
https://repo.maven.apache.org/maven2/com/sun/xml/fastinfoset/FastInfoset/2.1.0/FastInfoset-2.1.0.pom
https://repo.maven.apache.org/maven2/com/sun/xml/fastinfoset/FastInfoset/2.0.0/FastInfoset-2.0.0.pom
https://repo.maven.apache.org/maven2/com/sun/xml/fastinfoset/fastinfoset-project/1.2.13/fastinfoset-project-1.2.13.pom
https://repo.maven.apache.org/maven2/com/sun/xml/fastinfoset/fastinfoset-project/2.1.0/fastinfoset-project-2.1.0.pom
https://repo.maven.apache.org/maven2/com/sun/xml/fastinfoset/fastinfoset-project/2.0.0/fastinfoset-project-2.0.0.pom
https://repo.maven.apache.org/maven2/com/tunnelvisionlabs/antlr4-annotations/4.5/antlr4-annotations-4.5.pom
https://repo.maven.apache.org/maven2/com/tunnelvisionlabs/antlr4-annotations/4.9.0/antlr4-annotations-4.9.0.pom
https://repo.maven.apache.org/maven2/com/tunnelvisionlabs/antlr4-master/4.5/antlr4-master-4.5.pom
@@ -567,8 +567,8 @@ https://repo.maven.apache.org/maven2/de/undercouch/gradle-download-task/3.4.3/gr
https://repo.maven.apache.org/maven2/de/undercouch/gradle-download-task/4.0.2/gradle-download-task-4.0.2.pom
https://repo.maven.apache.org/maven2/it/unimi/dsi/fastutil/7.2.0/fastutil-7.2.0.pom
https://repo.maven.apache.org/maven2/jakarta/activation/jakarta.activation-api/2.1.0/jakarta.activation-api-2.1.0.pom
https://repo.maven.apache.org/maven2/jakarta/xml/bind/jakarta.xml.bind-api-parent/4.0.0/jakarta.xml.bind-api-parent-4.0.0.pom
https://repo.maven.apache.org/maven2/jakarta/xml/bind/jakarta.xml.bind-api/4.0.0/jakarta.xml.bind-api-4.0.0.pom
https://repo.maven.apache.org/maven2/jakarta/xml/bind/jakarta.xml.bind-api-parent/4.0.0-RC3/jakarta.xml.bind-api-parent-4.0.0-RC3.pom
https://repo.maven.apache.org/maven2/jakarta/xml/bind/jakarta.xml.bind-api/4.0.0-RC3/jakarta.xml.bind-api-4.0.0-RC3.pom
https://repo.maven.apache.org/maven2/javax/activation/activation/1.1/activation-1.1.pom
https://repo.maven.apache.org/maven2/javax/activation/javax.activation-api/1.2.0/javax.activation-api-1.2.0.pom
https://repo.maven.apache.org/maven2/javax/annotation/javax.annotation-api/1.2/javax.annotation-api-1.2.pom
@@ -619,22 +619,17 @@ https://repo.maven.apache.org/maven2/net/sf/proguard/proguard-parent/6.0.3/progu
https://repo.maven.apache.org/maven2/net/sf/proguard/proguard-parent/6.3.0beta1/proguard-parent-6.3.0beta1.pom
https://repo.maven.apache.org/maven2/org/abego/treelayout/org.abego.treelayout.core/1.0.1/org.abego.treelayout.core-1.0.1.pom
https://repo.maven.apache.org/maven2/org/antlr/ST4/4.0.8/ST4-4.0.8.pom
https://repo.maven.apache.org/maven2/org/antlr/ST4/4.3.3/ST4-4.3.3.pom
https://repo.maven.apache.org/maven2/org/antlr/ST4/4.3.1/ST4-4.3.1.pom
https://repo.maven.apache.org/maven2/org/antlr/antlr4-master/4.5.2-1/antlr4-master-4.5.2-1.pom
https://repo.maven.apache.org/maven2/org/antlr/antlr4-master/4.5.3/antlr4-master-4.5.3.pom
https://repo.maven.apache.org/maven2/org/antlr/antlr4-master/4.10.1/antlr4-master-4.10.1.pom
https://repo.maven.apache.org/maven2/org/antlr/antlr4-master/4.9.3/antlr4-master-4.9.3.pom
https://repo.maven.apache.org/maven2/org/antlr/antlr4-runtime/4.5.2-1/antlr4-runtime-4.5.2-1.pom
https://repo.maven.apache.org/maven2/org/antlr/antlr4-runtime/4.10.1/antlr4-runtime-4.10.1.pom
https://repo.maven.apache.org/maven2/org/antlr/antlr4-runtime/4.9.3/antlr4-runtime-4.9.3.pom
https://repo.maven.apache.org/maven2/org/antlr/antlr4/4.5.3/antlr4-4.5.3.pom
https://repo.maven.apache.org/maven2/org/antlr/antlr-master/3.3/antlr-master-3.3.pom
https://repo.maven.apache.org/maven2/org/antlr/antlr-master/3.5.2/antlr-master-3.5.2.pom
https://repo.maven.apache.org/maven2/org/antlr/antlr-master/3.5.3/antlr-master-3.5.3.pom
https://repo.maven.apache.org/maven2/org/antlr/antlr-runtime/3.3/antlr-runtime-3.3.pom
https://repo.maven.apache.org/maven2/org/antlr/antlr-runtime/3.5.2/antlr-runtime-3.5.2.pom
https://repo.maven.apache.org/maven2/org/antlr/antlr-runtime/3.5.3/antlr-runtime-3.5.3.pom
https://repo.maven.apache.org/maven2/org/antlr/antlr/3.5.2/antlr-3.5.2.pom
https://repo.maven.apache.org/maven2/org/antlr/stringtemplate/3.2.1/stringtemplate-3.2.1.pom
https://repo.maven.apache.org/maven2/org/antlr/stringtemplate/4.0.2/stringtemplate-4.0.2.pom
https://repo.maven.apache.org/maven2/org/apache/ant/ant-launcher/1.8.0/ant-launcher-1.8.0.pom
https://repo.maven.apache.org/maven2/org/apache/ant/ant-parent/1.8.0/ant-parent-1.8.0.pom
https://repo.maven.apache.org/maven2/org/apache/ant/ant/1.8.0/ant-1.8.0.pom
@@ -647,12 +642,13 @@ https://repo.maven.apache.org/maven2/org/apache/apache/13/apache-13.pom
https://repo.maven.apache.org/maven2/org/apache/apache/15/apache-15.pom
https://repo.maven.apache.org/maven2/org/apache/apache/16/apache-16.pom
https://repo.maven.apache.org/maven2/org/apache/apache/18/apache-18.pom
https://repo.maven.apache.org/maven2/org/apache/apache/19/apache-19.pom
https://repo.maven.apache.org/maven2/org/apache/apache/21/apache-21.pom
https://repo.maven.apache.org/maven2/org/apache/apache/23/apache-23.pom
https://repo.maven.apache.org/maven2/org/apache/apache/25/apache-25.pom
https://repo.maven.apache.org/maven2/org/apache/commons/commons-compress/1.8.1/commons-compress-1.8.1.pom
https://repo.maven.apache.org/maven2/org/apache/commons/commons-compress/1.12/commons-compress-1.12.pom
https://repo.maven.apache.org/maven2/org/apache/commons/commons-lang3/3.3.2/commons-lang3-3.3.2.pom
https://repo.maven.apache.org/maven2/org/apache/commons/commons-lang3/3.8.1/commons-lang3-3.8.1.pom
https://repo.maven.apache.org/maven2/org/apache/commons/commons-lang3/3.9/commons-lang3-3.9.pom
https://repo.maven.apache.org/maven2/org/apache/commons/commons-lang3/3.12.0/commons-lang3-3.12.0.pom
https://repo.maven.apache.org/maven2/org/apache/commons/commons-parent/5/commons-parent-5.pom
@@ -665,6 +661,7 @@ https://repo.maven.apache.org/maven2/org/apache/commons/commons-parent/34/common
https://repo.maven.apache.org/maven2/org/apache/commons/commons-parent/35/commons-parent-35.pom
https://repo.maven.apache.org/maven2/org/apache/commons/commons-parent/39/commons-parent-39.pom
https://repo.maven.apache.org/maven2/org/apache/commons/commons-parent/42/commons-parent-42.pom
https://repo.maven.apache.org/maven2/org/apache/commons/commons-parent/47/commons-parent-47.pom
https://repo.maven.apache.org/maven2/org/apache/commons/commons-parent/48/commons-parent-48.pom
https://repo.maven.apache.org/maven2/org/apache/commons/commons-parent/52/commons-parent-52.pom
https://repo.maven.apache.org/maven2/org/apache/geronimo/genesis/genesis-default-flava/2.3/genesis-default-flava-2.3.pom
@@ -705,40 +702,39 @@ https://repo.maven.apache.org/maven2/org/apache/httpcomponents/project/7/project
https://repo.maven.apache.org/maven2/org/apache/maven/maven-ant-tasks/2.1.3/maven-ant-tasks-2.1.3.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-artifact-manager/2.2.1/maven-artifact-manager-2.2.1.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-artifact/2.2.1/maven-artifact-2.2.1.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-artifact/3.8.5/maven-artifact-3.8.5.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-builder-support/3.8.5/maven-builder-support-3.8.5.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-compat/3.8.5/maven-compat-3.8.5.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-core/3.8.5/maven-core-3.8.5.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-artifact/3.8.4/maven-artifact-3.8.4.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-builder-support/3.8.4/maven-builder-support-3.8.4.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-compat/3.8.4/maven-compat-3.8.4.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-core/3.8.4/maven-core-3.8.4.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-error-diagnostics/2.2.1/maven-error-diagnostics-2.2.1.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-model-builder/3.8.5/maven-model-builder-3.8.5.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-model-builder/3.8.4/maven-model-builder-3.8.4.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-model/2.2.1/maven-model-2.2.1.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-model/3.8.5/maven-model-3.8.5.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-model/3.8.4/maven-model-3.8.4.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-parent/10/maven-parent-10.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-parent/11/maven-parent-11.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-parent/19/maven-parent-19.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-parent/34/maven-parent-34.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-parent/35/maven-parent-35.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-plugin-api/3.8.5/maven-plugin-api-3.8.5.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-plugin-api/3.8.4/maven-plugin-api-3.8.4.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-plugin-registry/2.2.1/maven-plugin-registry-2.2.1.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-profile/2.2.1/maven-profile-2.2.1.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-project-builder/3.0-alpha-2/maven-project-builder-3.0-alpha-2.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-project/2.2.1/maven-project-2.2.1.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-project/3.0-alpha-2/maven-project-3.0-alpha-2.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-repository-metadata/2.2.1/maven-repository-metadata-2.2.1.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-repository-metadata/3.8.5/maven-repository-metadata-3.8.5.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-resolver-provider/3.8.5/maven-resolver-provider-3.8.5.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-settings-builder/3.8.5/maven-settings-builder-3.8.5.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-repository-metadata/3.8.4/maven-repository-metadata-3.8.4.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-resolver-provider/3.8.4/maven-resolver-provider-3.8.4.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-settings-builder/3.8.4/maven-settings-builder-3.8.4.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-settings/2.2.1/maven-settings-2.2.1.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-settings/3.8.5/maven-settings-3.8.5.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven-settings/3.8.4/maven-settings-3.8.4.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven/2.2.1/maven-2.2.1.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven/3.0-alpha-2/maven-3.0-alpha-2.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven/3.8.5/maven-3.8.5.pom
https://repo.maven.apache.org/maven2/org/apache/maven/resolver/maven-resolver-api/1.8.0/maven-resolver-api-1.8.0.pom
https://repo.maven.apache.org/maven2/org/apache/maven/resolver/maven-resolver-impl/1.8.0/maven-resolver-impl-1.8.0.pom
https://repo.maven.apache.org/maven2/org/apache/maven/resolver/maven-resolver-named-locks/1.8.0/maven-resolver-named-locks-1.8.0.pom
https://repo.maven.apache.org/maven2/org/apache/maven/resolver/maven-resolver-spi/1.8.0/maven-resolver-spi-1.8.0.pom
https://repo.maven.apache.org/maven2/org/apache/maven/resolver/maven-resolver-util/1.8.0/maven-resolver-util-1.8.0.pom
https://repo.maven.apache.org/maven2/org/apache/maven/resolver/maven-resolver/1.8.0/maven-resolver-1.8.0.pom
https://repo.maven.apache.org/maven2/org/apache/maven/maven/3.8.4/maven-3.8.4.pom
https://repo.maven.apache.org/maven2/org/apache/maven/resolver/maven-resolver-api/1.7.3/maven-resolver-api-1.7.3.pom
https://repo.maven.apache.org/maven2/org/apache/maven/resolver/maven-resolver-impl/1.7.3/maven-resolver-impl-1.7.3.pom
https://repo.maven.apache.org/maven2/org/apache/maven/resolver/maven-resolver-named-locks/1.7.3/maven-resolver-named-locks-1.7.3.pom
https://repo.maven.apache.org/maven2/org/apache/maven/resolver/maven-resolver-spi/1.7.3/maven-resolver-spi-1.7.3.pom
https://repo.maven.apache.org/maven2/org/apache/maven/resolver/maven-resolver-util/1.7.3/maven-resolver-util-1.7.3.pom
https://repo.maven.apache.org/maven2/org/apache/maven/resolver/maven-resolver/1.7.3/maven-resolver-1.7.3.pom
https://repo.maven.apache.org/maven2/org/apache/maven/shared/maven-shared-components/34/maven-shared-components-34.pom
https://repo.maven.apache.org/maven2/org/apache/maven/shared/maven-shared-utils/3.3.4/maven-shared-utils-3.3.4.pom
https://repo.maven.apache.org/maven2/org/apache/maven/wagon/wagon-file/1.0-beta-6/wagon-file-1.0-beta-6.pom
@@ -753,8 +749,8 @@ https://repo.maven.apache.org/maven2/org/apache/maven/wagon/wagon-provider-api/1
https://repo.maven.apache.org/maven2/org/apache/maven/wagon/wagon-provider-api/3.5.1/wagon-provider-api-3.5.1.pom
https://repo.maven.apache.org/maven2/org/apache/maven/wagon/wagon/1.0-beta-6/wagon-1.0-beta-6.pom
https://repo.maven.apache.org/maven2/org/apache/maven/wagon/wagon/3.5.1/wagon-3.5.1.pom
https://repo.maven.apache.org/maven2/org/apache/xbean/xbean-reflect/4.21/xbean-reflect-4.21.pom
https://repo.maven.apache.org/maven2/org/apache/xbean/xbean/4.21/xbean-4.21.pom
https://repo.maven.apache.org/maven2/org/apache/xbean/xbean-reflect/4.20/xbean-reflect-4.20.pom
https://repo.maven.apache.org/maven2/org/apache/xbean/xbean/4.20/xbean-4.20.pom
https://repo.maven.apache.org/maven2/org/apiguardian/apiguardian-api/1.1.0/apiguardian-api-1.1.0.pom
https://repo.maven.apache.org/maven2/org/assertj/assertj-core/1.7.1/assertj-core-1.7.1.pom
https://repo.maven.apache.org/maven2/org/assertj/assertj-core/3.8.0/assertj-core-3.8.0.pom
@@ -769,7 +765,7 @@ https://repo.maven.apache.org/maven2/org/bouncycastle/bcprov-jdk15on/1.60/bcprov
https://repo.maven.apache.org/maven2/org/bouncycastle/bcprov-jdk15on/1.65/bcprov-jdk15on-1.65.pom
https://repo.maven.apache.org/maven2/org/bouncycastle/bcprov-jdk15on/1.70/bcprov-jdk15on-1.70.pom
https://repo.maven.apache.org/maven2/org/checkerframework/checker-qual/2.5.2/checker-qual-2.5.2.pom
https://repo.maven.apache.org/maven2/org/checkerframework/checker-qual/3.21.4/checker-qual-3.21.4.pom
https://repo.maven.apache.org/maven2/org/checkerframework/checker-qual/3.21.2/checker-qual-3.21.2.pom
https://repo.maven.apache.org/maven2/org/codehaus/codehaus-parent/4/codehaus-parent-4.pom
https://repo.maven.apache.org/maven2/org/codehaus/groovy/groovy-all/2.4.15/groovy-all-2.4.15.pom
https://repo.maven.apache.org/maven2/org/codehaus/mojo/animal-sniffer-annotations/1.14/animal-sniffer-annotations-1.14.pom
@@ -825,8 +821,7 @@ https://repo.maven.apache.org/maven2/org/easymock/easymockclassextension/3.2/eas
https://repo.maven.apache.org/maven2/org/easymock/easymock-parent/3.2/easymock-parent-3.2.pom
https://repo.maven.apache.org/maven2/org/easymock/easymock-parent/4.3/easymock-parent-4.3.pom
https://repo.maven.apache.org/maven2/org/easymock/easymock/4.3/easymock-4.3.pom
https://repo.maven.apache.org/maven2/org/eclipse/angus/angus-activation-project/1.0.0/angus-activation-project-1.0.0.pom
https://repo.maven.apache.org/maven2/org/eclipse/angus/angus-activation/1.0.0/angus-activation-1.0.0.pom
https://repo.maven.apache.org/maven2/org/eclipse/ee4j/project/1.0.6/project-1.0.6.pom
https://repo.maven.apache.org/maven2/org/eclipse/ee4j/project/1.0.7/project-1.0.7.pom
https://repo.maven.apache.org/maven2/org/eclipse/jdt/core/compiler/ecj/4.4.2/ecj-4.4.2.pom
https://repo.maven.apache.org/maven2/org/eclipse/jdt/core/compiler/ecj/4.4/ecj-4.4.pom
@@ -836,21 +831,21 @@ https://repo.maven.apache.org/maven2/org/eclipse/sisu/org.eclipse.sisu.plexus/0.
https://repo.maven.apache.org/maven2/org/eclipse/sisu/sisu-inject/0.3.5/sisu-inject-0.3.5.pom
https://repo.maven.apache.org/maven2/org/eclipse/sisu/sisu-plexus/0.3.5/sisu-plexus-0.3.5.pom
https://repo.maven.apache.org/maven2/org/glassfish/jaxb/jaxb-bom/2.2.11/jaxb-bom-2.2.11.pom
https://repo.maven.apache.org/maven2/org/glassfish/jaxb/jaxb-bom/4.0.0-M4/jaxb-bom-4.0.0-M4.pom
https://repo.maven.apache.org/maven2/org/glassfish/jaxb/jaxb-bom/3.0.2/jaxb-bom-3.0.2.pom
https://repo.maven.apache.org/maven2/org/glassfish/jaxb/jaxb-core/2.2.11/jaxb-core-2.2.11.pom
https://repo.maven.apache.org/maven2/org/glassfish/jaxb/jaxb-core/4.0.0-M4/jaxb-core-4.0.0-M4.pom
https://repo.maven.apache.org/maven2/org/glassfish/jaxb/jaxb-core/3.0.2/jaxb-core-3.0.2.pom
https://repo.maven.apache.org/maven2/org/glassfish/jaxb/jaxb-runtime/2.2.11/jaxb-runtime-2.2.11.pom
https://repo.maven.apache.org/maven2/org/glassfish/jaxb/txw2/2.2.11/txw2-2.2.11.pom
https://repo.maven.apache.org/maven2/org/glassfish/jaxb/txw2/4.0.0-M4/txw2-4.0.0-M4.pom
https://repo.maven.apache.org/maven2/org/glassfish/jaxb/txw2/3.0.2/txw2-3.0.2.pom
https://repo.maven.apache.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.pom
https://repo.maven.apache.org/maven2/org/hamcrest/hamcrest-core/2.2/hamcrest-core-2.2.pom
https://repo.maven.apache.org/maven2/org/hamcrest/hamcrest-library/1.3/hamcrest-library-1.3.pom
https://repo.maven.apache.org/maven2/org/hamcrest/hamcrest-parent/1.3/hamcrest-parent-1.3.pom
https://repo.maven.apache.org/maven2/org/hamcrest/hamcrest/2.2/hamcrest-2.2.pom
https://repo.maven.apache.org/maven2/org/jacoco/org.jacoco.build/0.7.4.201502262128/org.jacoco.build-0.7.4.201502262128.pom
https://repo.maven.apache.org/maven2/org/jacoco/org.jacoco.build/0.8.8/org.jacoco.build-0.8.8.pom
https://repo.maven.apache.org/maven2/org/jacoco/org.jacoco.build/0.8.7/org.jacoco.build-0.8.7.pom
https://repo.maven.apache.org/maven2/org/jacoco/org.jacoco.core/0.7.4.201502262128/org.jacoco.core-0.7.4.201502262128.pom
https://repo.maven.apache.org/maven2/org/jacoco/org.jacoco.core/0.8.8/org.jacoco.core-0.8.8.pom
https://repo.maven.apache.org/maven2/org/jacoco/org.jacoco.core/0.8.7/org.jacoco.core-0.8.7.pom
https://repo.maven.apache.org/maven2/org/jacoco/org.jacoco.report/0.7.4.201502262128/org.jacoco.report-0.7.4.201502262128.pom
https://repo.maven.apache.org/maven2/org/jboss/weld/weld-parent/26/weld-parent-26.pom
https://repo.maven.apache.org/maven2/org/jboss/weld/weld-parent/36/weld-parent-36.pom
@@ -912,7 +907,6 @@ https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-common/1
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-common/1.4.31/kotlin-stdlib-common-1.4.31.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-common/1.5.31/kotlin-stdlib-common-1.5.31.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-common/1.6.10/kotlin-stdlib-common-1.6.10.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-common/1.6.20/kotlin-stdlib-common-1.6.20.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.2.71/kotlin-stdlib-jdk7-1.2.71.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.3.20/kotlin-stdlib-jdk7-1.3.20.pom
https://repo.maven.apache.org/maven2/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.3.50/kotlin-stdlib-jdk7-1.3.50.pom
@@ -950,7 +944,7 @@ https://repo.maven.apache.org/maven2/org/junit/junit-bom/5.8.2/junit-bom-5.8.2.p
https://repo.maven.apache.org/maven2/org/junit/jupiter/junit-jupiter-api/5.7.0/junit-jupiter-api-5.7.0.pom
https://repo.maven.apache.org/maven2/org/junit/platform/junit-platform-commons/1.7.0/junit-platform-commons-1.7.0.pom
https://repo.maven.apache.org/maven2/org/jvnet/staxex/stax-ex/1.7.7/stax-ex-1.7.7.pom
https://repo.maven.apache.org/maven2/org/jvnet/staxex/stax-ex/2.1.0/stax-ex-2.1.0.pom
https://repo.maven.apache.org/maven2/org/jvnet/staxex/stax-ex/2.1.0-M1/stax-ex-2.1.0-M1.pom
https://repo.maven.apache.org/maven2/org/mockito/mockito-core/2.23.0/mockito-core-2.23.0.pom
https://repo.maven.apache.org/maven2/org/mockito/mockito-core/2.28.2/mockito-core-2.28.2.pom
https://repo.maven.apache.org/maven2/org/mockito/mockito-core/3.6.28/mockito-core-3.6.28.pom
@@ -966,12 +960,12 @@ https://repo.maven.apache.org/maven2/org/ow2/asm/asm-analysis/5.1/asm-analysis-5
https://repo.maven.apache.org/maven2/org/ow2/asm/asm-analysis/6.0/asm-analysis-6.0.pom
https://repo.maven.apache.org/maven2/org/ow2/asm/asm-analysis/7.0/asm-analysis-7.0.pom
https://repo.maven.apache.org/maven2/org/ow2/asm/asm-analysis/7.2/asm-analysis-7.2.pom
https://repo.maven.apache.org/maven2/org/ow2/asm/asm-analysis/9.3/asm-analysis-9.3.pom
https://repo.maven.apache.org/maven2/org/ow2/asm/asm-analysis/9.2/asm-analysis-9.2.pom
https://repo.maven.apache.org/maven2/org/ow2/asm/asm-commons/5.1/asm-commons-5.1.pom
https://repo.maven.apache.org/maven2/org/ow2/asm/asm-commons/6.0/asm-commons-6.0.pom
https://repo.maven.apache.org/maven2/org/ow2/asm/asm-commons/7.0/asm-commons-7.0.pom
https://repo.maven.apache.org/maven2/org/ow2/asm/asm-commons/7.2/asm-commons-7.2.pom
https://repo.maven.apache.org/maven2/org/ow2/asm/asm-commons/9.3/asm-commons-9.3.pom
https://repo.maven.apache.org/maven2/org/ow2/asm/asm-commons/9.2/asm-commons-9.2.pom
https://repo.maven.apache.org/maven2/org/ow2/asm/asm-debug-all/5.0.1/asm-debug-all-5.0.1.pom
https://repo.maven.apache.org/maven2/org/ow2/asm/asm-debug-all/6.0_BETA/asm-debug-all-6.0_BETA.pom
https://repo.maven.apache.org/maven2/org/ow2/asm/asm-parent/5.0.1/asm-parent-5.0.1.pom
@@ -984,7 +978,7 @@ https://repo.maven.apache.org/maven2/org/ow2/asm/asm-tree/5.1/asm-tree-5.1.pom
https://repo.maven.apache.org/maven2/org/ow2/asm/asm-tree/6.0/asm-tree-6.0.pom
https://repo.maven.apache.org/maven2/org/ow2/asm/asm-tree/7.0/asm-tree-7.0.pom
https://repo.maven.apache.org/maven2/org/ow2/asm/asm-tree/7.2/asm-tree-7.2.pom
https://repo.maven.apache.org/maven2/org/ow2/asm/asm-tree/9.3/asm-tree-9.3.pom
https://repo.maven.apache.org/maven2/org/ow2/asm/asm-tree/9.2/asm-tree-9.2.pom
https://repo.maven.apache.org/maven2/org/ow2/asm/asm-util/5.1/asm-util-5.1.pom
https://repo.maven.apache.org/maven2/org/ow2/asm/asm-util/6.0/asm-util-6.0.pom
https://repo.maven.apache.org/maven2/org/ow2/asm/asm-util/7.0/asm-util-7.0.pom
@@ -994,7 +988,7 @@ https://repo.maven.apache.org/maven2/org/ow2/asm/asm/5.1/asm-5.1.pom
https://repo.maven.apache.org/maven2/org/ow2/asm/asm/6.0/asm-6.0.pom
https://repo.maven.apache.org/maven2/org/ow2/asm/asm/7.0/asm-7.0.pom
https://repo.maven.apache.org/maven2/org/ow2/asm/asm/7.2/asm-7.2.pom
https://repo.maven.apache.org/maven2/org/ow2/asm/asm/9.3/asm-9.3.pom
https://repo.maven.apache.org/maven2/org/ow2/asm/asm/9.2/asm-9.2.pom
https://repo.maven.apache.org/maven2/org/ow2/ow2/1.3/ow2-1.3.pom
https://repo.maven.apache.org/maven2/org/ow2/ow2/1.5/ow2-1.5.pom
https://repo.maven.apache.org/maven2/org/robolectric/annotations/4.3/annotations-4.3.pom
@@ -1019,12 +1013,12 @@ https://repo.maven.apache.org/maven2/org/robolectric/utils-reflector/4.3/utils-r
https://repo.maven.apache.org/maven2/org/robolectric/utils-reflector/4.4/utils-reflector-4.4.pom
https://repo.maven.apache.org/maven2/org/robolectric/utils/4.3/utils-4.3.pom
https://repo.maven.apache.org/maven2/org/robolectric/utils/4.4/utils-4.4.pom
https://repo.maven.apache.org/maven2/org/slf4j/jcl-over-slf4j/2.0.0-alpha7/jcl-over-slf4j-2.0.0-alpha7.pom
https://repo.maven.apache.org/maven2/org/slf4j/jul-to-slf4j/2.0.0-alpha7/jul-to-slf4j-2.0.0-alpha7.pom
https://repo.maven.apache.org/maven2/org/slf4j/slf4j-api/2.0.0-alpha7/slf4j-api-2.0.0-alpha7.pom
https://repo.maven.apache.org/maven2/org/slf4j/slf4j-jdk14/2.0.0-alpha7/slf4j-jdk14-2.0.0-alpha7.pom
https://repo.maven.apache.org/maven2/org/slf4j/slf4j-parent/2.0.0-alpha7/slf4j-parent-2.0.0-alpha7.pom
https://repo.maven.apache.org/maven2/org/slf4j/slf4j-simple/2.0.0-alpha7/slf4j-simple-2.0.0-alpha7.pom
https://repo.maven.apache.org/maven2/org/slf4j/jcl-over-slf4j/2.0.0-alpha6/jcl-over-slf4j-2.0.0-alpha6.pom
https://repo.maven.apache.org/maven2/org/slf4j/jul-to-slf4j/2.0.0-alpha6/jul-to-slf4j-2.0.0-alpha6.pom
https://repo.maven.apache.org/maven2/org/slf4j/slf4j-api/2.0.0-alpha6/slf4j-api-2.0.0-alpha6.pom
https://repo.maven.apache.org/maven2/org/slf4j/slf4j-jdk14/2.0.0-alpha6/slf4j-jdk14-2.0.0-alpha6.pom
https://repo.maven.apache.org/maven2/org/slf4j/slf4j-parent/2.0.0-alpha6/slf4j-parent-2.0.0-alpha6.pom
https://repo.maven.apache.org/maven2/org/slf4j/slf4j-simple/2.0.0-alpha6/slf4j-simple-2.0.0-alpha6.pom
https://repo.maven.apache.org/maven2/org/sonatype/buildsupport/buildsupport/5/buildsupport-5.pom
https://repo.maven.apache.org/maven2/org/sonatype/buildsupport/buildsupport/12/buildsupport-12.pom
https://repo.maven.apache.org/maven2/org/sonatype/buildsupport/public-parent/5/public-parent-5.pom
+1 -1
View File
@@ -10,6 +10,7 @@ react-native-community_masked-view
react-native-community_netinfo
react-native-community_slider
react-native-config
react-native-dark-mode
react-native-device-info
react-native-dialogs
react-native-fast-image
@@ -26,7 +27,6 @@ react-native-navigation
react-native-nfc-manager
react-native-notifications
react-native-permissions
react-native-randombytes
react-native-reanimated
react-native-safe-area-context
react-native-shake
+3 -3
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
# This script is a wrapper around nix-build with some niceties.
set -e
GIT_ROOT=$(cd "${BASH_SOURCE%/*}" && git rev-parse --show-toplevel)
@@ -8,7 +8,7 @@ source "${GIT_ROOT}/scripts/colors.sh"
source "${GIT_ROOT}/nix/scripts/source.sh"
# cleanup for artifacts created during builds
cleanup() {
function cleanup() {
# clear trapped signals
trap - EXIT ERR INT QUIT
# do the actual cleanup, ignore failure
@@ -29,7 +29,7 @@ if [[ -n "${_NIX_CLEAN}" ]]; then
fi
# build output will end up under /nix, we have to extract it
extractResults() {
function extractResults() {
local nixResultPath="$1"
mkdir -p "${resultPath}"
cp -vfr ${nixResultPath}/* "${resultPath}" | sed 's#'${PWD}'#.#'
+9 -9
View File
@@ -5,16 +5,16 @@ set -e
GIT_ROOT=$(cd "${BASH_SOURCE%/*}" && git rev-parse --show-toplevel)
source "${GIT_ROOT}/nix/scripts/source.sh"
log() { echo "$@" 1>&2; }
function log() { echo "$@" 1>&2; }
# helpers for getting related paths in Nix store
getSources() { nix-store --query --binding src "${1}"; }
getOutputs() { nix-store --query --outputs "${1}"; }
getDrvFiles() { nix-store --query --deriver "${1}"; }
getReferrers() { nix-store --query --referrers "${1}"; }
getRoots() { nix-store --query --roots "${1}"; }
function getSources() { nix-store --query --binding src "${1}"; }
function getOutputs() { nix-store --query --outputs "${1}"; }
function getDrvFiles() { nix-store --query --deriver "${1}"; }
function getReferrers() { nix-store --query --referrers "${1}"; }
function getRoots() { nix-store --query --roots "${1}"; }
findRelated() {
function findRelated() {
path="${1}"
found+=("${path}")
if [[ "${path}" =~ .*.chroot ]]; then
@@ -51,7 +51,7 @@ findRelated() {
}
# used to find things to delete based on a regex
findByRegex() {
function findByRegex() {
regex="${1}"
log "Searching by regex: '${regex}'"
@@ -70,7 +70,7 @@ findByRegex() {
}
# used to find things to delete based on a given path
findByResult() {
function findByResult() {
mainPath="${1}"
log "Searching by result: '${mainPath}'"
-37
View File
@@ -1,37 +0,0 @@
#!/usr/bin/env bash
# Checking group ownership to identify installation type.
file_group() {
UNAME=$(uname -s)
if [[ "${UNAME}" == "Linux" ]]; then
stat -Lc "%G" "${1}" 2>/dev/null
elif [[ "${UNAME}" == "Darwin" ]]; then
stat -Lf "%Sg" "${1}" 2>/dev/null
fi
}
os_name() {
source /etc/os-release 2>/dev/null
echo "${NAME}"
}
is_arch_linux() {
[[ -f /etc/arch-release ]]
}
nix_install_type() {
NIX_STORE_DIR_GROUP=$(file_group /nix/store)
if [[ "$(os_name)" =~ NixOS ]]; then
echo "nixos"
elif [[ "${NIX_STORE_DIR_GROUP}" == "nixbld" ]]; then
echo "multi"
elif [[ "${NIX_STORE_DIR_GROUP}" == "${USER}" ]]; then
echo "single"
elif [[ "${NIX_STORE_DIR_GROUP}" == "" ]]; then
echo "No Nix installtion detected!" >&2
echo "none"
else
echo "Unknown Nix installtion type!" >&2
exit 1
fi
}
+5 -5
View File
@@ -23,13 +23,13 @@ source "${GIT_ROOT}/scripts/colors.sh"
# More concise output from 'time'
export TIMEFORMAT="Done in: %Es"
removeDir() {
function removeDir() {
[[ ! -d "${tmp}" ]] && return
chmod -R u+w "${tmp}"
rm -rf "${tmp}"
}
copyNodeModules() {
function copyNodeModules() {
local src="${1}"
local dst="${2}"
# WARNING: The ../ is there to avoid a Nix builtins.path bug:
@@ -51,7 +51,7 @@ copyNodeModules() {
# Find files that were modified and should cause a re-copying of node modules.
# Some files are generated/modified by build processes and should be ignored.
findFilesNewerThan() {
function findFilesNewerThan() {
local sentinel="${1}"
local dir="${2}"
find ${dir} -type f -writable \
@@ -63,7 +63,7 @@ findFilesNewerThan() {
-print
}
nodeModulesUnchanged() {
function nodeModulesUnchanged() {
local src="$1"
local dst="$2"
local sentinelFile="${dst}/.copied~"
@@ -98,7 +98,7 @@ nodeModulesUnchanged() {
return 0
}
replaceNodeModules() {
function replaceNodeModules() {
local src="$1"
local dst="$2"
local sentinelFile="${dst}/.copied~"
+15 -73
View File
@@ -1,82 +1,24 @@
#!/usr/bin/env bash
# This script removes all Nix files.
set -e
GIT_ROOT=$(cd "${BASH_SOURCE%/*}" && git rev-parse --show-toplevel)
source "${GIT_ROOT}/nix/scripts/lib.sh"
source "${GIT_ROOT}/scripts/colors.sh"
nix_purge_multi_user() {
sudo systemctl stop nix-daemon.socket
sudo systemctl stop nix-daemon.service
sudo systemctl disable nix-daemon.socket
sudo systemctl disable nix-daemon.service
sudo systemctl daemon-reload
sudo rm -fr /etc/nix
sudo rm -f /etc/profile.d/nix.sh*
# Remove nix build users and groups
for NIX_USER in $(awk -F: '/nixbld/{print $1}' /etc/passwd); do
sudo userdel "${NIX_USER}"
done
sudo groupdel nixbld
# Restore old shell profiles
NIX_PROFILE_FILES=(
/etc/bash.bashrc /etc/bashrc /etc/bash/bashrc
/etc/zsh.zshhrc /etc/zshrc /etc/zsh/zshrc
)
for NIX_FILE in "${NIX_PROFILE_FILES[@]}"; do
if [[ -f "${NIX_FILE}.backup-before-nix" ]]; then
sudo mv -f "${NIX_FILE}.backup-before-nix" "${NIX_FILE}"
fi
done
}
nix_purge_user_profile() {
sudo rm -rf \
~/.nix-* \
~/.cache/nix \
~/.config/nixpkgs \
${GIT_ROOT}/.nix-gcroots
}
nix_purge_root() {
NIX_ROOT="/nix"
if [[ $(uname -s) == "Darwin" ]]; then
# Special case due to read-only root on MacOS Catalina
NIX_ROOT="/opt/nix"
fi
if [[ -z "${NIX_ROOT}" ]]; then
echo -e "${RED}Unable to identify Nix root!${RST}" >&2
exit 1
fi
sudo rm -fr "${NIX_ROOT}"
}
NIX_INSTALL_TYPE=$(nix_install_type)
if [[ "${1}" == "--force" ]] && [[ "${NIX_INSTALL_TYPE}" != "nixos" ]]; then
echo -e "${YLW}Purge forced, no checks performed!${RST}" >&2
nix_purge_multi_user
nix_purge_user_profile
nix_purge_root
exit
fi
# Purging /nix on NixOS would be disasterous
if [[ "${NIX_INSTALL_TYPE}" == "nixos" ]]; then
echo -e "${RED}You should not purge Nix files on NixOS!${RST}" >&2
exit
elif [[ "${NIX_INSTALL_TYPE}" == "none" ]]; then
echo -e "${YLW}Nothing to remove, Nix not installed.${RST}" >&2
exit
elif [[ "${NIX_INSTALL_TYPE}" == "multi" ]]; then
echo -e "${YLW}Detected multi-user Nix installation.${RST}" >&2
nix_purge_multi_user
elif [[ "${NIX_INSTALL_TYPE}" == "single" ]]; then
echo -e "${YLW}Detected single-user Nix installation.${RST}" >&2
nix_purge_user_profile
if [[ -f "/etc/os-release" ]]; then
OS_NAME=$(awk -F= '/^NAME/{print $2}' /etc/os-release)
if [[ "$OS_NAME" == "NixOS" ]]; then
echo -e "${RED}You should not purge Nix files on NixOS!${RST}" >&2
exit
fi
fi
nix_purge_root
NIX_ROOT="/nix"
if [[ $(uname -s) == "Darwin" ]]; then
# Special case due to read-only root on MacOS Catalina
NIX_ROOT="/opt/nix"
fi
sudo rm -rf ${NIX_ROOT}/* ~/.nix-profile ~/.nix-defexpr ~/.nix-channels ~/.cache/nix ~/.status .nix-gcroots
echo -e "${GRN}Purged all Nix files from your system.${RST}" >&2
+30 -52
View File
@@ -1,73 +1,51 @@
#!/usr/bin/env bash
# This script installs a specific version of Nix.
set -eo pipefail
GIT_ROOT=$(cd "${BASH_SOURCE%/*}" && git rev-parse --show-toplevel)
source "${GIT_ROOT}/nix/scripts/lib.sh"
source "${GIT_ROOT}/scripts/colors.sh"
NIX_VERSION="2.6.1"
NIX_VERSION="2.3.12"
NIX_INSTALL_URL="https://nixos.org/releases/nix/nix-${NIX_VERSION}/install"
NIX_INSTALL_SHA256="a63732b4f3628ce97e096dbda88e3cb9851ff6b4f94b5cd43feb257126437b9d"
NIX_INSTALL_SHA256="468a49a1cef293d59508bb3b62625dfcd99ec00334a14309f125cf8de513d5f1"
NIX_INSTALL_PATH="/tmp/nix-install-${NIX_VERSION}"
install_nix() {
# Download installer and verify SHA256>
curl -sSf "${NIX_INSTALL_URL}" -o "${NIX_INSTALL_PATH}"
echo "${NIX_INSTALL_SHA256} ${NIX_INSTALL_PATH}" | sha256sum -c
chmod +x "${NIX_INSTALL_PATH}"
# Identify installation type.
if [[ -z "${NIX_INSTALL_OPTS}" ]]; then
if [[ "$(uname -r)" =~ microsoft ]]; then
# Systemd is not started by default on WSL.
NIX_INSTALL_OPTS="--no-daemon"
elif [[ "$(uname -s)" == "Darwin" ]]; then
# Single-user not supported on Darwin.
NIX_INSTALL_OPTS="--daemon"
elif [[ "$(uname -s)" == "Linux" ]]; then
# Open file limit issues on Linux.
# https://github.com/NixOS/nix/issues/6007
# Alson known issues with nix-daemon.socket on Arch.
NIX_INSTALL_OPTS="--no-daemon"
fi
fi
# Run the installer
"${NIX_INSTALL_PATH}" "${NIX_INSTALL_OPTS}"
if [[ $? -eq 0 ]]; then
echo -e "${GRN}The Nix package manager was successfully installed.${RST}"
else
echo -e "${RED}Failed to install Nix package manager!${RST}" >&2
echo "Please see: https://nixos.org/nix/manual/#chap-installation" >&2
exit 1
fi
function install_nix() {
# Don't break people's profiles
export NIX_INSTALLER_NO_MODIFY_PROFILE=1
# Fix for installing on MacOS Catalina
export NIX_IGNORE_SYMLINK_STORE=1
# Download installer and verify SHA256
curl -s "${NIX_INSTALL_URL}" -o "${NIX_INSTALL_PATH}"
echo "${NIX_INSTALL_SHA256} ${NIX_INSTALL_PATH}" | sha256sum -c
chmod +x "${NIX_INSTALL_PATH}"
# Run the installer
"${NIX_INSTALL_PATH}" --no-daemon
if [ $? -eq 0 ]; then
echo -e "${GRN}The Nix package manager was successfully installed.${RST}"
else
echo -e "${RED}Failed to install Nix package manager!${RST}" >&2
echo "Please see: https://nixos.org/nix/manual/#chap-installation" >&2
exit 1
fi
}
if [[ ! -x "$(command -v sha256sum)" ]]; then
echo -e "${RED}The 'sha256sum' utility is required for Nix installation.${RST}" >&2
echo -e "${YLW}Install 'coreutils' package on your system.${RST}" >&2
exit 1
if [[ ! -x "$(command -v git)" ]]; then
echo -e "${RED}The 'curl' utility is required for Nix installation.${RST}" >&2
exit 1
fi
if [[ ! -x "$(command -v curl)" ]]; then
echo -e "${RED}The 'curl' utility is required for Nix installation.${RST}" >&2
exit 1
fi
if [[ "$(source /etc/os-release 2>/dev/null && echo "${NAME}")" == *NixOS* ]]; then
echo -e "${GRN}Already running NixOS.${RST}"
exit
if [[ "$(source /etc/os-release && echo "${NAME}")" == *NixOS* ]]; then
echo -e "${GRN}Already running NixOS.${RST}"
exit
fi
if [[ -x "$(command -v nix)" ]]; then
echo -e "${GRN}Nix package manager already installed.${RST}"
exit
echo -e "${GRN}Nix package manager already installed.${RST}"
exit
fi
if [[ "${IN_NIX_SHELL}" == 'pure' ]]; then
echo -e "${GRN}Already in a pure Nix shell.${RST}"
exit
echo -e "${GRN}Already in a pure Nix shell.${RST}"
exit
fi
# If none of the checks before succeeded we need to install Nix
+22 -30
View File
@@ -1,41 +1,33 @@
#!/usr/bin/env bash
# This script makes sure we have Nix tools available
set -e
GIT_ROOT=$(cd "${BASH_SOURCE%/*}" && git rev-parse --show-toplevel)
source "${GIT_ROOT}/nix/scripts/lib.sh"
source "${GIT_ROOT}/scripts/colors.sh"
source_nix_profile() {
NIX_INSTALL_TYPE=$(nix_install_type)
if [[ "${NIX_INSTALL_TYPE}" == "multi" ]]; then
source "/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh"
elif [[ "${NIX_INSTALL_TYPE}" == "single" ]]; then
source "${HOME}/.nix-profile/etc/profile.d/nix.sh"
elif [[ "${NIX_INSTALL_TYPE}" == "nixops" ]]; then
echo "Sourcing profile not necessary on NixOS!" >&2
fi
}
main() {
# Just stop if Nix is already available
if [[ -x $(command -v nix) ]]; then
return
fi
# Location of profile script for Nix that adjusts PATH
export NIX_PROFILE_SH="${HOME}/.nix-profile/etc/profile.d/nix.sh"
function source_nix() {
# Just stop if Nix is already available
if [[ -x $(command -v nix) ]]; then
return
elif [[ -f "${NIX_PROFILE_SH}" ]]; then
# Load Nix profile if it exists
source "${NIX_PROFILE_SH}"
return
else
# Setup Nix if not available
if [[ ! -d /nix ]]; then
${GIT_ROOT}/nix/scripts/setup.sh
fi
${GIT_ROOT}/nix/scripts/setup.sh
fi
# Load Nix profile
source_nix_profile
# Load Nix profile
source "${NIX_PROFILE_SH}"
# Verify Nix is available
if [[ ! -x $(command -v nix) ]]; then
echo -e "${RED}Nix not available, sourcing profile failed!${RST}" >&2
exit 1
fi
# Verify Nix is available
if [[ ! -x $(command -v nix) ]]; then
echo "Nix not available, sourcing profile failed!" > /dev/stderr
exit 1
fi
}
main
source_nix
+11 -11
View File
@@ -12,9 +12,9 @@
},
"dependencies": {
"@react-native-community/async-storage": "^1.11.0",
"@react-native-community/audio-toolkit": "git+https://github.com/tbenr/react-native-audio-toolkit.git#refs/tags/v2.0.3-status-v6",
"@react-native-community/audio-toolkit": "git+https://github.com/tbenr/react-native-audio-toolkit.git#v2.0.3-status-v6",
"@react-native-community/blur": "^3.6.0",
"@react-native-community/cameraroll": "git+https://github.com/status-im/react-native-cameraroll.git#refs/tags/v4.0.4-status.0",
"@react-native-community/cameraroll": "git+https://github.com/status-im/react-native-cameraroll.git#v4.0.4-status.0",
"@react-native-community/clipboard": "^1.2.2",
"@react-native-community/hooks": "^2.5.1",
"@react-native-community/masked-view": "^0.1.6",
@@ -23,7 +23,7 @@
"@react-native-community/slider": "^3.0.0",
"@walletconnect/client": "^2.0.0-beta.23",
"@walletconnect/client-legacy": "npm:@walletconnect/client@^1.7.1",
"bignumber.js": "git+https://github.com/status-im/bignumber.js.git#refs/tags/v4.0.2-status",
"bignumber.js": "git+https://github.com/status-im/bignumber.js.git#v4.0.2-status",
"buffer": "^5.4.2",
"chance": "^1.1.0",
"create-react-class": "^15.6.2",
@@ -41,7 +41,7 @@
"react-native-background-timer": "^2.1.1",
"react-native-blob-util": "^0.13.18",
"react-native-camera-kit": "^8.0.4",
"react-native-config": "git+https://github.com/status-im/react-native-config.git#refs/tags/v1.4.2-status",
"react-native-config": "git+https://github.com/status-im/react-native-config.git#v1.4.2-status",
"react-native-device-info": "^7.4.0",
"react-native-dialogs": "^1.0.4",
"react-native-draggable-flatlist": "^3.0.3",
@@ -50,10 +50,10 @@
"react-native-fs": "^2.14.1",
"react-native-gesture-handler": "^1.8.0",
"react-native-haptic-feedback": "^1.9.0",
"react-native-image-crop-picker": "git+https://github.com/status-im/react-native-image-crop-picker.git#refs/tags/v0.36.2-status.0",
"react-native-image-crop-picker": "git+https://github.com/status-im/react-native-image-crop-picker.git#v0.36.2-status.0",
"react-native-image-resizer": "^1.2.3",
"react-native-image-viewing": "git+https://github.com/status-im/react-native-image-viewing.git#refs/tags/v0.2.1.status",
"react-native-keychain": "git+https://github.com/status-im/react-native-keychain.git#refs/tags/v.3.0.0-5-status",
"react-native-image-viewing": "git+https://github.com/status-im/react-native-image-viewing.git#v0.2.1.status",
"react-native-keychain": "git+https://github.com/status-im/react-native-keychain.git#v.3.0.0-5-status",
"react-native-languages": "^3.0.2",
"react-native-linear-gradient": "^2.5.6",
"react-native-mail": "^6.1.1",
@@ -67,11 +67,11 @@
"react-native-shake": "^3.3.1",
"react-native-share": "^7.0.1",
"react-native-splash-screen": "^3.2.0",
"react-native-status-keycard": "git+https://github.com/status-im/react-native-status-keycard.git#refs/tags/v2.5.37",
"react-native-status-keycard": "git+https://github.com/status-im/react-native-status-keycard.git#v2.5.37",
"react-native-svg": "^9.8.4",
"react-native-touch-id": "^4.4.1",
"react-native-webview": "git+https://github.com/status-im/react-native-webview.git#refs/tags/v11.16.0-status",
"rn-emoji-keyboard": "git+https://github.com/status-im/rn-emoji-keyboard.git#refs/tags/v0.4.3",
"react-native-webview": "git+https://github.com/status-im/react-native-webview.git#v11.16.0-status",
"rn-emoji-keyboard": "git+https://github.com/status-im/rn-emoji-keyboard.git#v0.4.2",
"tdigest": "^0.1.1",
"web3-utils": "^1.2.1"
},
@@ -86,7 +86,7 @@
"jest": "^25.1.0",
"nyc": "^14.1.1",
"process": "0.11.10",
"rn-snoopy": "git+https://github.com/status-im/rn-snoopy.git#refs/tags/v2.0.2-status",
"rn-snoopy": "git+https://github.com/status-im/rn-snoopy.git#v2.0.2-status",
"shadow-cljs": "^2.10.14"
}
}
+6 -8
View File
@@ -50,9 +50,6 @@ Examples:
# Using tag name
${SCRIPT_FILE} v2.1.1
# Using commit SHA1
${SCRIPT_FILE} 1a2b3c4d
# Using PR number
${SCRIPT_FILE} PR-2134
END
@@ -85,12 +82,13 @@ STATUS_GO_BRANCH_SHA1=$(echo "${STATUS_GO_MATCHING_REFS}" | grep 'refs/heads' |
# Prefer tag over branch if both are found
if [[ -n "${STATUS_GO_TAG_SHA1}" ]]; then
STATUS_GO_COMMIT_SHA1="${STATUS_GO_TAG_SHA1}"
elif [[ -n "${STATUS_GO_BRANCH_SHA1}" ]]; then
STATUS_GO_COMMIT_SHA1="${STATUS_GO_BRANCH_SHA1}"
elif [[ "${#STATUS_GO_VERSION}" -gt 4 ]]; then
STATUS_GO_COMMIT_SHA1="${STATUS_GO_VERSION}"
else
echo "ERROR: Input not a tag or branch, but too short to be a SHA1!" >&2
STATUS_GO_COMMIT_SHA1="${STATUS_GO_BRANCH_SHA1}"
fi
if [[ -z "${STATUS_GO_COMMIT_SHA1}" ]]; then
echo "ERROR: Failed to find a SHA1 for rev '${STATUS_GO_VERSION}'."
echo "NOTE: To set SHA1 you can just edit ${VERSION_FILE} by hand."
exit 1
fi
+2 -6
View File
@@ -1,11 +1,7 @@
(ns quo.theme
(:require [quo.design-system.colors :as colors]
[reagent.core :as reagent]))
(:require [quo.design-system.colors :as colors]))
(def theme (reagent/atom nil))
(defn dark? []
(= :dark @theme))
(def theme (atom nil))
(defn get-theme []
@theme)
+13 -40
View File
@@ -1,10 +1,10 @@
(ns quo2.components.button
(:require [quo.react-native :as rn]
[status-im.ui.components.icons.icons :as icons]
[quo2.foundations.colors :as colors]
[quo2.components.text :as text]
[quo.theme :as theme]
[reagent.core :as reagent]
[quo2.components.icon :as quo2.icons]))
[reagent.core :as reagent]))
(def themes {:light {:primary {:icon-color colors/white
:label {:style {:color colors/white}}
@@ -16,9 +16,9 @@
:background-color {:default colors/primary-50-opa-20
:pressed colors/primary-50-opa-40
:disabled colors/primary-50-opa-20}}
:grey {:icon-color colors/black
:grey {:icon-color colors/neutral-50
:label {:style {:color colors/black}}
:background-color {:default colors/neutral-20
:background-color {:default colors/neutral-40
:pressed colors/neutral-30
:disabled colors/neutral-20}}
:outline {:icon-color colors/neutral-50
@@ -61,7 +61,7 @@
:pressed colors/danger-40
:disabled colors/danger-50}}}})
(defn style-container [type size disabled background-color border-color icon above width before after]
(defn style-container [type size disabled background-color border-color icon above]
(merge {:height size
:align-items :center
:justify-content :center
@@ -74,14 +74,7 @@
32 10
24 8))
:background-color background-color
:padding-horizontal (when-not (or icon before after)
(case size 56 16 40 16 32 12 24 8))
:padding-left (when-not (or icon before)
(case size 56 16 40 16 32 12 24 8))
:padding-right (when-not (or icon after)
(case size 56 16 40 16 32 12 24 8))}
(when width
{:width width})
:padding-horizontal (if icon 0 (case size 56 16 40 16 32 12 24 8))}
(when icon
{:width size})
(when border-color
@@ -104,15 +97,14 @@
[button {:icon true} :main-icons/close-circle]"
[_ _]
(let [pressed (reagent/atom false)]
(fn [{:keys [on-press disabled type size before after above width
(fn [{:keys [on-press disabled type size before after above
on-long-press accessibility-label icon]
:or {type :primary
size 40}}
children]
(let [{:keys [icon-color background-color label border-color]}
(get-in themes [(theme/get-theme) type])
state (cond disabled :disabled @pressed :pressed :else :default)
icon-size (when (= 24 size) 12)]
state (cond disabled :disabled @pressed :pressed :else :default)]
[rn/touchable-without-feedback (merge {:disabled disabled
:accessibility-label accessibility-label}
(when on-press
@@ -126,33 +118,17 @@
{:on-press-out (fn []
(reset! pressed nil))})
[rn/view {:style (style-container
type
size
disabled
(get background-color state)
(get border-color state)
icon
above
width
before
after)}
[rn/view {:style (style-container type size disabled (get background-color state) (get border-color state) icon above)}
(when above
[rn/view
[quo2.icons/icon above {:container-style {:margin-bottom 2}
:color icon-color
:size icon-size}]])
[icons/icon above {:color icon-color}]])
(when before
[rn/view
[quo2.icons/icon before {:container-style {:margin-left (if (= size 40) 12 8)
:margin-right 4}
:color icon-color
:size icon-size}]])
[icons/icon before {:color icon-color}]])
[rn/view
(cond
icon
[quo2.icons/icon children {:color icon-color
:size icon-size}]
[icons/icon children {:color icon-color}]
(string? children)
[text/text (merge {:size (when (#{56 24} size) :paragraph-2)
@@ -165,7 +141,4 @@
children)]
(when after
[rn/view
[quo2.icons/icon after {:container-style {:margin-left 4
:margin-right (if (= size 40) 12 8)}
:color icon-color
:size icon-size}]])]]))))
[icons/icon after {:color icon-color}]])]]))))
-10
View File
@@ -1,10 +0,0 @@
(ns quo2.components.icon
(:require [status-im.ui.components.icons.icons :as icons]))
(defn icon
([icon-name] (icon icon-name nil))
([icon-name {:keys [size] :as props}]
(let [size (or size 20)]
[icons/icon (str (name icon-name) size) (merge props
{:width size
:height size})])))
+1 -1
View File
@@ -5,7 +5,7 @@
(defn tabs [{:keys [default-active on-change]}]
(let [active-tab-id (reagent/atom default-active)]
(fn [{:keys [data size] :or {size 32}}]
(fn [{:keys [data size]}]
(let [active-id @active-tab-id]
[rn/view {:flex-direction :row}
(for [{:keys [label id]} data]
+2 -6
View File
@@ -1,6 +1,5 @@
(ns quo2.foundations.colors
(:require [clojure.string :as string]
[quo.theme :as theme]))
(:require [clojure.string :as string]))
(defn alpha [value opacity]
(if (string/starts-with? value "#")
@@ -174,7 +173,4 @@
(def info-50-opa-10 (alpha info-50 0.1))
(def info-50-opa-20 (alpha info-50 0.2))
(def info-50-opa-30 (alpha info-50 0.3))
(def info-50-opa-40 (alpha info-50 0.4))
(defn theme-colors [light dark]
(if (theme/dark?) dark light))
(def info-50-opa-40 (alpha info-50 0.4))
+5 -6
View File
@@ -2,24 +2,23 @@
(def heading-1 {:font-size 27
:line-height 32.4
:letter-spacing -0.5})
:letter-spacing -2.1})
(def heading-2 {:font-size 19
:line-height 25.65
:letter-spacing -0.4})
:letter-spacing -1.6})
(def paragraph-1 {:font-size 15
:line-height 21.75
:letter-spacing -0.1})
:letter-spacing -0.9})
(def paragraph-2 {:font-size 13
:line-height 18.2
:letter-spacing 0})
:letter-spacing -0.3})
(def label {:font-size 11
:line-height 15.62
:letter-spacing -0.055
:text-transform :uppercase})
:letter-spacing -0.055})
(def font-regular {:font-family "Inter-Regular"}) ; 400
+4 -4
View File
@@ -70,12 +70,12 @@
:theme :before :after)
{:on-press #(println "Hello world!")}
(when @above
{:above :main-icons2/placeholder})
{:above :main-icons/close-circle})
(when @before
{:before :main-icons2/placeholder})
{:before :main-icons/back})
(when @after
{:after :main-icons2/placeholder}))
(if @icon :main-icons2/placeholder @label)]]])))
{:after :main-icons/next}))
(if @icon :main-icons/close-circle @label)]]])))
(defn preview-button []
[rn/view {:background-color (:ui-background @colors/theme)
+5 -1
View File
@@ -8,8 +8,12 @@
(def descriptor [{:label "Size:"
:key :size
:type :select
:options [{:key 28
:options [{:key 32
:value "32"}
{:key 28
:value "28"}
{:key 24
:value "24"}
{:key 20
:value "20"}]}])
+5 -1
View File
@@ -10,8 +10,12 @@
:type :select
:options [{:key 32
:value "32"}
{:key 28
:value "28"}
{:key 24
:value "24"}]}])
:value "24"}
{:key 20
:value "20"}]}])
(defn cool-preview []
(let [state (reagent/atom {:size 32})]
+2
View File
@@ -27,6 +27,8 @@
:value "Medium"}
{:key :semi-bold
:value "Semi-bold"}
{:key :bold
:value "Bold"}
{:key :monospace
:value "Monospace"}]}])
+7 -12
View File
@@ -48,7 +48,7 @@
(defn active-chat? [cofx chat-id]
(let [chat (get-chat cofx chat-id)]
(:active chat)))
(not (nil? chat))))
(defn foreground-chat?
[{{:keys [current-chat-id view-id]} :db} chat-id]
@@ -115,11 +115,11 @@
"Add chats to db and update"
[{:keys [db] :as cofx} chats]
(let [{:keys [all-chats chats-home-list removed-chats]}
(reduce (fn [acc {:keys [chat-id profile-public-key timeline? community-id active muted] :as chat}]
(if (not (or active muted))
(reduce (fn [acc {:keys [chat-id profile-public-key timeline? community-id active] :as chat}]
(if (not active)
(update acc :removed-chats conj chat-id)
(cond-> acc
(and (not profile-public-key) (not timeline?) (not community-id) active)
(and (not profile-public-key) (not timeline?) (not community-id))
(update :chats-home-list conj chat-id)
:always
(assoc-in [:all-chats chat-id] chat))))
@@ -135,9 +135,7 @@
(update :chats #(apply dissoc % removed-chats))
(update :chats-home-list set/difference removed-chats))}
(when (not-empty removed-chats)
{:clear-message-notifications
[removed-chats
(get-in db [:multiaccount :remote-push-notifications-enabled?])]}))
{:clear-multiple-message-notifications removed-chats}))
leave-removed-chat)))
(fx/defn clear-history
@@ -179,9 +177,8 @@
[{:keys [db now] :as cofx} chat-id]
(fx/merge
cofx
{:db (-> (if (get-in db [:chats chat-id :muted])
(assoc-in db [:chats chat-id :active] false)
(update db :chats dissoc chat-id))
{:db (-> db
(update :chats dissoc chat-id)
(update :chats-home-list disj chat-id)
(assoc-in [:current-chat-id] nil))
::json-rpc/call [{:method "wakuext_deactivateChat"
@@ -225,8 +222,6 @@
{:events [:chat.ui/remove-chat]}
[{:keys [db now] :as cofx} chat-id]
(fx/merge cofx
{:clear-message-notifications
[[chat-id] (get-in db [:multiaccount :remote-push-notifications-enabled?])]}
(deactivate-chat chat-id)
(offload-messages chat-id)
(when (not (= (:view-id db) :home))
+14 -23
View File
@@ -7,8 +7,7 @@
[status-im.chat.models.message-list :as message-list]
[taoensso.timbre :as log]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.chat.models.pin-message :as models.pin-message]
[status-im.notifications-center.core :as notification-center]))
[status-im.chat.models.pin-message :as models.pin-message]))
(defn cursor->clock-value
[^js cursor]
@@ -24,10 +23,10 @@
[{:keys [db]} ^js new-chats-js]
(let [{:keys [all-chats chats-home-list]}
(reduce (fn [acc ^js chat-js]
(let [{:keys [chat-id profile-public-key timeline? community-id active] :as chat}
(let [{:keys [chat-id profile-public-key timeline? community-id] :as chat}
(data-store.chats/<-rpc-js chat-js)]
(cond-> acc
(and (not profile-public-key) (not timeline?) (not community-id) active)
(and (not profile-public-key) (not timeline?) (not community-id))
(update :chats-home-list conj chat-id)
:always
(assoc-in [:all-chats chat-id] chat))))
@@ -67,37 +66,29 @@
(fx/defn handle-mark-all-read-successful
{:events [::mark-all-read-successful]}
[{:keys [db] :as cofx} chat-id]
(fx/merge cofx
{:db (mark-chat-all-read db chat-id)}
(notification-center/get-activity-center-notifications-count)))
[{:keys [db]} chat-id]
{:db (mark-chat-all-read db chat-id)})
(fx/defn handle-mark-all-read-in-community-successful
{:events [::mark-all-read-in-community-successful]}
[{:keys [db] :as cofx} chat-ids]
(fx/merge cofx
{:db (reduce mark-chat-all-read db chat-ids)}
(notification-center/get-activity-center-notifications-count)))
[{:keys [db]} chat-ids]
{:db (reduce mark-chat-all-read db chat-ids)})
(fx/defn handle-mark-all-read
{:events [:chat.ui/mark-all-read-pressed :chat/mark-all-as-read]}
[{db :db} chat-id]
{:clear-message-notifications [[chat-id]
(get-in db [:multiaccount :remote-push-notifications-enabled?])]
[_ chat-id]
{:clear-message-notifications chat-id
::json-rpc/call [{:method (json-rpc/call-ext-method "markAllRead")
:params [chat-id]
:on-success #(re-frame/dispatch [::mark-all-read-successful chat-id])}]})
(fx/defn handle-mark-mark-all-read-in-community
{:events [:chat.ui/mark-all-read-in-community-pressed]}
[{db :db} community-id]
(let [community-chat-ids (map #(str community-id %)
(keys (get-in db [:communities community-id :chats])))]
{:clear-message-notifications [community-chat-ids
(get-in db [:multiaccount :remote-push-notifications-enabled?])]
::json-rpc/call [{:method (json-rpc/call-ext-method "markAllReadInCommunity")
:params [community-id]
:on-success #(re-frame/dispatch [::mark-all-read-in-community-successful %])}]}))
[_ community-id]
{:clear-message-notifications community-id
::json-rpc/call [{:method (json-rpc/call-ext-method "markAllReadInCommunity")
:params [community-id]
:on-success #(re-frame/dispatch [::mark-all-read-in-community-successful %])}]})
(fx/defn messages-loaded
"Loads more messages for current chat"
+1 -4
View File
@@ -247,10 +247,7 @@
(merge mentionable-users
(mentionable-contacts-from-identites all-contacts public-key (keys community-members)))
(= chat-type constants/public-chat-type)
(merge mentionable-users (select-keys mentionable-contacts (keys mentionable-users)))
:else mentionable-users)))
:else (merge mentionable-users mentionable-contacts))))
(def ending-chars "[\\s\\.,;:]")
(def ending-chars-regex (re-pattern ending-chars))
+9 -14
View File
@@ -103,8 +103,7 @@
[cofx response-js]
(fx/merge cofx
(handle-response cofx response-js)
(navigation/pop-to-root-tab :chat-stack)
(notification-center/get-activity-center-notifications-count)))
(navigation/pop-to-root-tab :chat-stack)))
(fx/defn joined
{:events [::joined ::requested-to-join]}
@@ -157,18 +156,14 @@
(fx/defn leave
{:events [::leave]}
[{:keys [db] :as cofx} community-id]
(let [community-chat-ids (map #(str community-id %)
(keys (get-in db [:communities community-id :chats])))]
{:clear-message-notifications [community-chat-ids
(get-in db [:multiaccount :remote-push-notifications-enabled?])]
::json-rpc/call [{:method "wakuext_leaveCommunity"
:params [community-id]
:js-response true
:on-success #(re-frame/dispatch [::left %])
:on-error #(do
(log/error "failed to leave community" community-id %)
(re-frame/dispatch [::failed-to-leave %]))}]}))
[cofx community-id]
{::json-rpc/call [{:method "wakuext_leaveCommunity"
:params [community-id]
:js-response true
:on-success #(re-frame/dispatch [::left %])
:on-error #(do
(log/error "failed to leave community" community-id %)
(re-frame/dispatch [::failed-to-leave %]))}]})
(fx/defn fetch [_]
{::json-rpc/call [{:method "wakuext_communities"
+1 -3
View File
@@ -44,9 +44,7 @@
{:db (-> db
(update :chats dissoc public-key)
(update :chats-home-list disj public-key)
(assoc-in [:contacts/contacts public-key :added] false))
:clear-message-notifications
[[public-key] (get-in db [:multiaccount :remote-push-notifications-enabled?])]}
(assoc-in [:contacts/contacts public-key :added] false))}
(notification-center/get-activity-center-notifications-count)
fxs)))
+1 -2
View File
@@ -97,8 +97,7 @@
:community-id (.-contentCommunityId chat)}
:last-clock-value (.-lastClockValue chat)
:profile-public-key (.-profile chat)
:highlight (.-highlight chat)
:active (.-active chat)}
:highlight (.-highlight chat)}
rpc->type
unmarshal-members))
+4 -7
View File
@@ -8,8 +8,7 @@
[status-im.navigation :as navigation]
[status-im.utils.fx :as fx]
[status-im.constants :as constants]
[status-im.i18n.i18n :as i18n]
[status-im.notifications-center.core :as notification-center]))
[status-im.i18n.i18n :as i18n]))
(fx/defn navigate-chat-updated
{:events [:navigate-chat-updated]}
@@ -21,11 +20,9 @@
(fx/defn handle-chat-removed
{:events [:chat-removed]}
[cofx response]
(fx/merge cofx
{:dispatch-n [[:sanitize-messages-and-process-response response]
[:pop-to-root-tab :chat-stack]]}
(notification-center/get-activity-center-notifications-count)))
[_ response]
{:dispatch-n [[:sanitize-messages-and-process-response response]
[:pop-to-root-tab :chat-stack]]})
(fx/defn handle-chat-update
{:events [:chat-updated]}
+1 -6
View File
@@ -143,13 +143,13 @@
{:events [::initialize-wallet]}
[{:keys [db] :as cofx} accounts tokens custom-tokens
favourites scan-all-tokens? new-account?]
(check-invalid-ens cofx)
(fx/merge
cofx
{:db (assoc db :multiaccount/accounts
(rpc->accounts accounts))
;; NOTE: Local notifications should be enabled only after wallet was started
::enable-local-notifications nil}
(check-invalid-ens)
(wallet/initialize-tokens tokens custom-tokens)
(wallet/initialize-favourites favourites)
(wallet/get-pending-transactions)
@@ -415,11 +415,6 @@
(when (= stored-key-uid key-uid)
(re-frame/dispatch [:chat.ui/navigate-to-chat chat-id])))))))))
(fx/defn check-last-chat
{:events [::check-last-chat]}
[{:keys [db]}]
{::open-last-chat (get-in db [:multiaccount :key-uid])})
(fx/defn get-chats-callback
{:events [::get-chats-callback]}
[{:keys [db] :as cofx}]
+2 -7
View File
@@ -13,8 +13,7 @@
[status-im.ui.screens.views :as views]
[status-im.utils.fx :as fx]
[status-im.utils.platform :as platform]
[taoensso.timbre :as log]
[status-im.multiaccounts.login.core :as login-core]))
[taoensso.timbre :as log]))
(def debug? ^boolean js/goog.DEBUG)
@@ -27,9 +26,6 @@
(defonce modals (atom []))
(defonce dissmissing (atom false))
(defonce set-navigation-default-options
(.setDefaultOptions Navigation (clj->js {:layout {:orientation "portrait"}})))
;; REGISTER COMPONENT (LAZY)
(defn reg-comp [key]
(log/debug "reg-comp" key)
@@ -207,8 +203,7 @@
(re-frame/dispatch-sync [::set-multiaccount-root])
(when @root-id
(reset! root-comp-id @root-id)
(.setRoot Navigation (clj->js (get (roots/roots) @root-id)))
(re-frame/dispatch [::login-core/check-last-chat])))
(.setRoot Navigation (clj->js (get (roots/roots) @root-id)))))
(.hide ^js splash-screen))))
(defn get-screen-component [comp]
+10 -11
View File
@@ -102,19 +102,18 @@
(pn-android/disable-notifications)
(.abandonPermissions ^js pn-ios))))
(defn clear-all-message-notifications []
(if platform/android?
(pn-android/clear-all-message-notifications)
(.removeAllDeliveredNotifications ^js pn-ios)))
(re-frame/reg-fx
:clear-message-notifications
(fn [[chat-ids remote-push-notifications-enabled?]]
(if remote-push-notifications-enabled?
(clear-all-message-notifications)
(when platform/android?
(doseq [chat-id chat-ids]
(pn-android/clear-message-notifications chat-id))))))
(fn [chat-id]
(when platform/android?
(pn-android/clear-message-notifications chat-id))))
(re-frame/reg-fx
:clear-multiple-message-notifications
(fn [chat-ids]
(when platform/android?
(doseq [chat-id chat-ids]
(pn-android/clear-message-notifications chat-id)))))
(fx/defn handle-enable-notifications-event
{:events [:notifications/registered-for-push-notifications]}
+6 -4
View File
@@ -43,10 +43,12 @@
(= our-installation-id (:installation-id b))
1
:else
(let [enabled-compare (compare (:enabled? b) (:enabled? a))]
(let [enabled-compare (compare (:enabled? b)
(:enabled? a))]
(if (not= 0 enabled-compare)
enabled-compare
(compare (:timestamp a) (:timestamp b))))))
(compare (:timestamp b)
(:timestamp a))))))
(defn sort-installations
[our-installation-id installations]
@@ -187,10 +189,10 @@
:params [(or preferred-name name) identicon]
:on-success #(log/debug "successfully synced devices")}]}))
(defn installation<-rpc [{:keys [metadata id enabled timestamp]}]
(defn installation<-rpc [{:keys [metadata id enabled]}]
{:installation-id id
:name (:name metadata)
:timestamp timestamp
:timestamp (:timestamp metadata)
:device-type (:deviceType metadata)
:enabled? enabled})
-7
View File
@@ -2339,13 +2339,6 @@
(fn [[contact] _]
(:added contact)))
(re-frame/reg-sub
:contacts/contact-blocked?
(fn [[_ identity] _]
[(re-frame/subscribe [:contacts/contact-by-identity identity])])
(fn [[contact] _]
(:blocked contact)))
(re-frame/reg-sub
:contacts/contact-two-names-by-identity
(fn [[_ identity] _]
+2 -14
View File
@@ -50,7 +50,6 @@
^js bookmarks (.-bookmarks response-js)
^js settings (.-settings response-js)
^js cleared-histories (.-clearedHistories response-js)
^js identity-images (.-identityImages response-js)
sync-handler (when-not process-async process-response)]
(cond
@@ -101,7 +100,7 @@
(js-delete response-js "bookmarks")
(fx/merge cofx
(process-next response-js sync-handler)
(browser/handle-bookmarks bookmarks-clj)))
(browser/handle-bookmarks cofx bookmarks-clj)))
(seq pin-messages)
(let [pin-messages (types/js->clj pin-messages)]
@@ -160,18 +159,7 @@
visibility-status-updates-clj)))
(seq settings)
(do
(js-delete response-js "settings")
(fx/merge cofx
(process-next response-js sync-handler)
(update.core/set-many-js settings)))
(seq identity-images)
(let [images-clj (map types/js->clj identity-images)]
(js-delete response-js "identityImages")
(fx/merge cofx
(process-next response-js sync-handler)
(update.core/optimistic :images images-clj)))
(update.core/set-many-js cofx settings)
(some? current-visibility-status)
(let [current-visibility-status-clj (types/js->clj current-visibility-status)]
@@ -22,8 +22,7 @@
[status-im.utils.identicon :as identicon]
[status-im.ui.components.keyboard-avoid-presentation :as kb-presentation]
[status-im.ui.components.animation :as animation]
[status-im.ui.screens.chat.photos :as photos]
[status-im.utils.db :as utils.db])
[status-im.ui.screens.chat.photos :as photos])
(:require-macros [status-im.utils.views :as views]))
(defn- render-row [row]
@@ -46,20 +45,19 @@
icon])
(defn- input-icon
[state new-contact? entered-nickname blocked?]
[state new-contact? entered-nickname]
(let [icon (if new-contact? :main-icons/add :main-icons/arrow-right)]
(cond
(= state :searching)
(case state
:searching
[icon-wrapper colors/gray
[react/activity-indicator {:color colors/white-persist}]]
(and (= state :valid) (not blocked?))
:valid
[react/touchable-highlight
{:on-press #(debounce/dispatch-and-chill [:contact.ui/contact-code-submitted new-contact? entered-nickname] 3000)}
[icon-wrapper colors/blue
[icons/icon icon {:color colors/white-persist}]]]
:else
[icon-wrapper colors/gray
[icons/icon icon {:color colors/white-persist}]])))
@@ -253,12 +251,9 @@
:return-key-type :done
:auto-correct false}])
(defn new-contact []
(let [{:keys [state ens-name public-key error]} @(re-frame/subscribe [:contacts/new-identity])
entered-nickname (reagent/atom "")
blocked? (and
(utils.db/valid-public-key? (or public-key ""))
@(re-frame/subscribe [:contacts/contact-blocked? public-key]))]
(views/defview new-contact []
(views/letsubs [{:keys [state ens-name public-key error]} [:contacts/new-identity]
entered-nickname (reagent/atom "")]
[react/view {:style {:flex 1}}
[topbar/topbar
{:title (i18n/label :t/new-contact)
@@ -289,7 +284,7 @@
:return-key-type :go}]]
[react/view {:justify-content :center
:align-items :center}
[input-icon state true @entered-nickname blocked?]]]
[input-icon state true @entered-nickname]]]
[react/view {:min-height 30 :justify-content :flex-end :margin-bottom 16}
[quo/text {:style {:margin-horizontal 16}
:size :small
+19 -22
View File
@@ -92,14 +92,13 @@
(defn calculate-quiet-time [synced-to
synced-from]
(when synced-from
(let [quiet-hours (quot (- synced-to synced-from)
(* 60 60))]
(if (<= quiet-hours 24)
(i18n/label :t/quiet-hours
{:quiet-hours quiet-hours})
(i18n/label :t/quiet-days
{:quiet-days (quot quiet-hours 24)})))))
(let [quiet-hours (quot (- synced-to synced-from)
(* 60 60))]
(if (<= quiet-hours 24)
(i18n/label :t/quiet-hours
{:quiet-hours quiet-hours})
(i18n/label :t/quiet-days
{:quiet-days (quot quiet-hours 24)}))))
(defview no-messages-community-chat-description-container [chat-id]
(letsubs [{:keys [synced-to synced-from]}
@@ -114,20 +113,18 @@
(defview no-messages-private-group-chat-description-container [chat-id]
(letsubs [{:keys [synced-to synced-from]}
[:chats/synced-to-and-from chat-id]]
(let [quiet-time (calculate-quiet-time synced-to
synced-from)]
[react/nested-text {:style (merge style/intro-header-description
{:margin-bottom 36})}
(if quiet-time
(i18n/label :t/empty-chat-description-public
{:quiet-hours quiet-time})
(i18n/label :t/cleared-chat-description-public))
[{:style {:color colors/blue}
:on-press #(list-selection/open-share
{:message
(i18n/label
:t/share-public-chat-text {:link (links/generate-link :public-chat :external chat-id)})})}
(i18n/label :t/empty-chat-description-public-share-this)]])))
[react/nested-text {:style (merge style/intro-header-description
{:margin-bottom 36})}
(let [quiet-time (calculate-quiet-time synced-to
synced-from)]
(i18n/label :t/empty-chat-description-public
{:quiet-hours quiet-time}))
[{:style {:color colors/blue}
:on-press #(list-selection/open-share
{:message
(i18n/label
:t/share-public-chat-text {:link (links/generate-link :public-chat :external chat-id)})})}
(i18n/label :t/empty-chat-description-public-share-this)]]))
(defview pending-invitation-description
[inviter-pk chat-name]
@@ -572,45 +572,31 @@
:source {:uri (contenthash/url (-> content :sticker :hash))}}]]
reaction-picker]))
(defmethod ->message constants/content-type-image
[{:keys [content in-popover? outgoing] :as message}
{:keys [on-long-press modal]
:as reaction-picker}]
(defmethod ->message constants/content-type-image [{:keys [content in-popover?] :as message} {:keys [on-long-press modal]
:as reaction-picker}]
[message-content-wrapper message
[message-content-image message
{:modal modal
:disabled in-popover?
:delay-long-press 100
:on-long-press (fn []
(on-long-press
(concat [{:on-press #(re-frame/dispatch [:chat.ui/reply-to-message message])
:id :reply
:label (i18n/label :t/message-reply)}
{:on-press #(re-frame/dispatch [:chat.ui/save-image-to-gallery (:image content)])
:id :save
:label (i18n/label :t/save)}]
(when (and outgoing config/delete-message-enabled?)
[{:on-press #(re-frame/dispatch [:chat.ui/soft-delete-message message])
:label (i18n/label :t/delete)
:id :delete}]))))}]
[message-content-image message {:modal modal
:disabled in-popover?
:delay-long-press 100
:on-long-press (fn []
(on-long-press
[{:on-press #(re-frame/dispatch [:chat.ui/reply-to-message message])
:id :reply
:label (i18n/label :t/message-reply)}
{:on-press #(re-frame/dispatch [:chat.ui/save-image-to-gallery (:image content)])
:id :save
:label (i18n/label :t/save)}]))}]
reaction-picker])
(defmethod ->message constants/content-type-audio
[{:keys [outgoing] :as message}
{:keys [on-long-press modal]
:as reaction-picker}]
(defmethod ->message constants/content-type-audio [message {:keys [on-long-press modal]
:as reaction-picker}]
(let [show-timestamp? (reagent/atom false)]
(fn [] [message-content-wrapper message
[react/touchable-highlight
(when-not modal
{:on-long-press
(fn [] (on-long-press (if (and outgoing config/delete-message-enabled?)
[{:on-press #(re-frame/dispatch [:chat.ui/soft-delete-message message])
:label (i18n/label :t/delete)
:id :delete}]
[])))
:on-press (fn []
(reset! show-timestamp? true))})
[react/touchable-highlight (when-not modal
{:on-long-press
(fn [] (on-long-press []))
:on-press (fn []
(reset! show-timestamp? true))})
[react/view (style/message-view-wrapper (:outgoing message))
[message-timestamp message show-timestamp?]
[react/view {:style (style/message-view message) :accessibility-label :audio-message}
+1 -2
View File
@@ -49,8 +49,7 @@
(i18n/label :t/group-membership-request)]]])))))
(defn add-contact-bar [public-key]
(when-not (or @(re-frame/subscribe [:contacts/contact-added? public-key])
@(re-frame/subscribe [:contacts/contact-blocked? public-key]))
(when-not @(re-frame/subscribe [:contacts/contact-added? public-key])
[react/touchable-highlight
{:on-press
#(re-frame/dispatch [:contact.ui/add-to-contact-pressed public-key])
@@ -21,9 +21,7 @@
:on-press #(re-frame/dispatch [:multiaccounts.ui/default-sync-period-switched id])}])
(views/defview default-sync-period-settings []
(views/letsubs [{:keys [default-sync-period]
:or {default-sync-period constants/one-day}}
[:multiaccount]]
(views/letsubs [{:keys [default-sync-period]} [:multiaccount]]
[react/view {:margin-top 8}
(when config/two-minutes-syncing?
[radio-item constants/two-mins default-sync-period])
@@ -67,11 +67,10 @@
:top 12
:left 16})
(defn title-text [title-text-width]
(def title-text
{:margin-left 72
:margin-top 12
:margin-right 50
:width title-text-width})
:margin-right 50})
(def notification-message-container
{:margin-left 72
@@ -85,4 +84,4 @@
(def community-info-container
{:flex-direction :row
:align-items :center})
:align-items :center})
@@ -19,8 +19,7 @@
{:keys [community-id]} (<sub [:chat-by-id chat-id])
{:keys [name]} @(re-frame/subscribe [:communities/community community-id])
contact (when message @(re-frame/subscribe [:contacts/contact-by-identity (message :from)]))
sender (when message (first @(re-frame/subscribe [:contacts/contact-two-names-by-identity (message :from)])))
title-text-width (* @(re-frame/subscribe [:dimensions/window-width]) 0.62)]
sender (when message (first @(re-frame/subscribe [:contacts/contact-two-names-by-identity (message :from)])))]
[react/touchable-opacity (merge {:style (styles/notification-container read)} opts)
[react/view {:style styles/notification-content-container}
(if (or
@@ -43,7 +42,7 @@
:accessibility-label :chat-name-or-sender-text
:ellipsize-mode :tail
:number-of-lines 1
:style (styles/title-text title-text-width)}
:style styles/title-text}
(if (or
(= type constants/activity-center-notification-type-mention)
(= type constants/activity-center-notification-type-reply))
@@ -37,10 +37,8 @@
:action #(re-frame/dispatch [:contact.ui/remove-contact-pressed contact])}]
[{:label (i18n/label :t/add-to-contacts)
:icon :main-icons/add-contact
:disabled blocked?
:accessibility-label :add-to-contacts-button
:action (when-not blocked?
#(re-frame/dispatch [:contact.ui/add-to-contact-pressed public-key nil ens-name]))}])
:action #(re-frame/dispatch [:contact.ui/add-to-contact-pressed public-key nil ens-name])}])
[{:label (i18n/label (if (or muted? blocked?) :t/unmute :t/mute))
:icon :main-icons/notification
:accessibility-label :mute-chat
+2 -5
View File
@@ -122,7 +122,6 @@
[status-im.ui.screens.wallet.send.views :as wallet.send]
[quo2.screens.main :as quo2.preview]
[status-im.utils.config :as config]))
;[quo2.foundations.colors :as quo2.colors]))
(def components
[{:name :chat-toolbar
@@ -358,11 +357,9 @@
{:name :wallet
:insets {:top false}
:on-focus [:wallet/tab-opened]
;;TODO wallet redesign
;;:options {:statusBar {:backgroundColor quo2.colors/neutral-5}}
:component wallet.accounts/accounts-overview-old}
:component wallet.accounts/accounts-overview}
{:name :wallet-account
;;TODO dynamic titleaccounts-overview
;;TODO dynamic title
:options {:topBar {:visible false}}
:component wallet.account/account}
{:name :add-new-account
@@ -33,9 +33,7 @@
(let [width (reagent/atom nil)]
(fn [uri show-close?]
[react/view {:style {:width @width
:align-items :center
:height image-max-dimension
:max-width :100%
:overflow :hidden
:opacity (if @width 1 0)
:border-radius 16
@@ -42,9 +42,7 @@
:accessory-text (cond
(= default-sync-period constants/two-mins)
(i18n/label :t/two-minutes)
(or
(nil? default-sync-period)
(= default-sync-period constants/one-day))
(= default-sync-period constants/one-day)
(i18n/label :t/one-day)
(= default-sync-period constants/three-days)
(i18n/label :t/three-days)
@@ -13,20 +13,14 @@
[status-im.utils.config :as config]
[status-im.ui.screens.wallet.account.styles :as styles]
[status-im.ui.screens.wallet.accounts.sheets :as sheets]
[status-im.ui.screens.wallet.accounts.common :as common]
[status-im.ui.screens.wallet.accounts.views :as accounts]
[status-im.ui.screens.wallet.transactions.views :as history]
[status-im.ui.components.tabs :as tabs]
[status-im.ui.screens.wallet.collectibles.views :as collectibles.views]
[status-im.ui.screens.wallet.buy-crypto.views :as buy-crypto]
[quo2.foundations.colors :as quo2.colors]
[status-im.utils.handlers :refer [<sub]]
[quo2.components.text :as quo2.text]
[quo2.components.button :as quo2.button]
[quo2.components.tabs :as quo2.tabs])
[status-im.ui.screens.wallet.buy-crypto.views :as buy-crypto])
(:require-macros [status-im.utils.views :as views]))
(def state (reagent/atom {:tab :assets}))
(def selected-tab (reagent/atom :tokens))
(defn button [label icon color handler]
[react/touchable-highlight {:on-press handler :style {:flex 1}}
@@ -104,27 +98,26 @@
{:style {:color colors/blue}}
(i18n/label :t/check-on-opensea)]]])
(views/defview assets-and-collections-new [address]
(views/defview assets-and-collections [address]
(views/letsubs [{:keys [tokens]} [:wallet/visible-assets-with-values address]
currency [:wallet/currency]
opensea-enabled? [:opensea-enabled?]
collectible-collection [:wallet/collectible-collection address]]
;ethereum-network? [:ethereum-network?]]
(let [tab @selected-tab]
collectible-collection [:wallet/collectible-collection address]
ethereum-network? [:ethereum-network?]]
(let [{:keys [tab]} @state]
[react/view {:flex 1}
[react/view {:padding-horizontal 20 :padding-bottom 20}
[quo2.tabs/tabs {:size 24
:on-change #(reset! selected-tab %)
:default-active :tokens
:data [{:id :tokens :label "Tokens"}
{:id :nft :label "NFTs"}
{:id :activity :label "Activity"}]}]]
[react/view {:flex-direction :row :margin-bottom 8 :padding-horizontal 4}
[tabs/tab-title state :assets (i18n/label :t/wallet-assets) (= tab :assets)]
(when ethereum-network?
[tabs/tab-title state :nft (i18n/label :t/wallet-collectibles) (= tab :nft)])
[tabs/tab-title state :history (i18n/label :t/history) (= tab :history)]]
[quo/separator {:style {:margin-top -8}}]
(cond
(= tab :tokens)
[react/scroll-view
(= tab :assets)
[:<>
(for [item tokens]
^{:key (:name item)}
[common/render-asset-new item nil nil (:code currency)])]
[accounts/render-asset item nil nil (:code currency)])]
(= tab :nft)
[:<>
[opensea-link address]
@@ -141,7 +134,7 @@
[react/view {:align-items :center :margin-top 32}
[react/text {:style {:color colors/gray}}
(i18n/label :t/no-collectibles)]]))]
(= tab :activity)
(= tab :history)
[transactions address])])))
(views/defview bottom-send-recv-buttons [{:keys [address type] :as account} anim-y]
@@ -208,76 +201,6 @@
:title (i18n/label :t/swap)
:on-press #(re-frame/dispatch [:open-modal :token-swap])}]])
(views/defview assets-and-collections [address]
(views/letsubs [{:keys [tokens]} [:wallet/visible-assets-with-values address]
currency [:wallet/currency]
opensea-enabled? [:opensea-enabled?]
collectible-collection [:wallet/collectible-collection address]
ethereum-network? [:ethereum-network?]]
(let [{:keys [tab]} @state]
[react/view {:flex 1}
[react/view {:flex-direction :row :margin-bottom 8 :padding-horizontal 4}
[tabs/tab-title state :assets (i18n/label :t/wallet-assets) (= tab :assets)]
(when ethereum-network?
[tabs/tab-title state :nft (i18n/label :t/wallet-collectibles) (= tab :nft)])
[tabs/tab-title state :history (i18n/label :t/history) (= tab :history)]]
[quo/separator {:style {:margin-top -8}}]
(cond
(= tab :assets)
[:<>
(for [item tokens]
^{:key (:name item)}
[common/render-asset item nil nil (:code currency)])]
(= tab :nft)
[:<>
[opensea-link address]
;; Hide collectibles behind a feature flag
(when config/collectibles-enabled?
(cond
(not opensea-enabled?)
[collectibles.views/enable-opensea-view]
(and opensea-enabled? (seq collectible-collection))
[collectibles.views/nft-collections address]
:else
[react/view {:align-items :center :margin-top 32}
[react/text {:style {:color colors/gray}}
(i18n/label :t/no-collectibles)]]))]
(= tab :history)
[transactions address])])))
(defn account-new [selected-account]
(let [;{:keys [name address] :as account} (<sub [:account-by-address selected-account])
currency (<sub [:wallet/currency])
portfolio-value (<sub [:account-portfolio-value selected-account])
width (<sub [:dimensions/window-width])
button-width (/ (- width 40 (* 2 12)) 3)]
;fetching-error (<sub [:wallet/fetching-error])]
[react/view {:flex 1
:background-color (quo2.colors/theme-colors quo2.colors/white quo2.colors/neutral-90)
:border-top-left-radius 20
:border-top-right-radius 20
:elevation 4
:shadow-opacity 1
:shadow-radius 20
:shadow-color (:shadow-01 @colors/theme)
:shadow-offset {:width 0 :height 4}}
[react/view {:padding 20}
[quo2.text/text {:size :heading-2 :weight :semi-bold} (str portfolio-value " " (:code currency))]]
[react/view
[react/scroll-view {:horizontal true :margin-bottom 32 :showsHorizontalScrollIndicator false}
[react/view {:width 20}]
[quo2.button/button {:size 56 :width button-width :above :main-icons2/placeholder} "Buy"]
[react/view {:width 12}]
[quo2.button/button {:size 56 :width button-width :type :secondary :above :main-icons2/placeholder} "Send"]
[react/view {:width 12}]
[quo2.button/button {:size 56 :width button-width :type :secondary :above :main-icons2/placeholder} "Receive"]
[react/view {:width 12}]
[quo2.button/button {:size 56 :width button-width :type :secondary :above :main-icons2/placeholder} "Swap"]
[react/view {:width 20}]]]
[assets-and-collections-new selected-account]]))
(views/defview account []
(views/letsubs [{:keys [name address] :as account} [:multiaccount/current-account]
fetching-error [:wallet/fetching-error]]
@@ -298,9 +221,9 @@
[{:nativeEvent {:contentOffset {:y scroll-y}}}]
{:useNativeDriver true})
:scrollEventThrottle 1
:refreshControl (common/refresh-control
:refreshControl (accounts/refresh-control
(and
@common/updates-counter
@accounts/updates-counter
@(re-frame/subscribe [:wallet/refreshing-history?])))}
(when fetching-error
[react/view {:style {:flex 1
@@ -1,87 +0,0 @@
(ns status-im.ui.screens.wallet.accounts.common
(:require [quo.core :as quo]
[status-im.wallet.utils :as wallet.utils]
[status-im.ui.screens.wallet.components.views :as wallet.components]
[status-im.ui.components.chat-icon.screen :as chat-icon]
[reagent.core :as reagent]
[quo.react-native :as rn]
[status-im.utils.utils :as utils.utils]
[re-frame.core :as re-frame]
[quo2.foundations.colors :as quo2.colors]
[quo2.components.text :as quo2.text]))
;; Note(rasom): sometimes `refreshing` might get stuck on iOS if action happened
;; too fast. By updating this atom in 1s we ensure that `refreshing?` property
;; is updated properly in this case.
(def updates-counter (reagent/atom 0))
(defn schedule-counter-reset []
(utils.utils/set-timeout
(fn []
(swap! updates-counter inc)
(when @(re-frame/subscribe [:wallet/refreshing-history?])
(schedule-counter-reset)))
1000))
(defn refresh-action []
(schedule-counter-reset)
(re-frame/dispatch [:wallet.ui/pull-to-refresh-history]))
(defn refresh-control [refreshing?]
(reagent/as-element
[rn/refresh-control
{:refreshing (boolean refreshing?)
:onRefresh refresh-action}]))
(defn render-asset [{:keys [icon decimals amount color value] :as token} _ _ currency]
[quo/list-item
{:title [quo/text {:weight :medium}
[quo/text {:weight :inherit}
(str (if amount
(wallet.utils/format-amount amount decimals)
"...")
" ")]
[quo/text {:color :secondary
:weight :inherit}
(wallet.utils/display-symbol token)]]
:subtitle (str (if value value "...") " " currency)
:accessibility-label (str (:symbol token) "-asset-value")
:icon (if icon
[wallet.components/token-icon icon]
[chat-icon/custom-icon-view-list (:name token) color])}])
(defn render-asset-new [{:keys [icon decimals amount color value name] :as token} _ _ currency]
[rn/view {:height 56 :margin-horizontal 8 :margin-top 4}
[rn/view {:position :absolute :left 12 :top 12}
(if icon
[wallet.components/token-icon (merge icon {:width 32 :height 32})]
[chat-icon/custom-icon-view-list (:name token) color])]
[rn/view {:position :absolute :left 52 :top 8 :right 12}
[rn/view {:flex-direction :row :justify-content :space-between :align-items :center}
[quo2.text/text {:weight :semi-bold :style {:height 22}}
name]
[quo2.text/text {:size :paragraph-2 :weight :medium}
(str (if value value "...") " " currency)]]
[quo2.text/text {:size :paragraph-2
:weight :medium
:style {:color (quo2.colors/theme-colors quo2.colors/neutral-50 quo2.colors/neutral-40)}}
(str (if amount
(wallet.utils/format-amount amount decimals)
"...")
" "
(wallet.utils/display-symbol token))]]]
#_[quo/list-item
{:title [quo/text {:weight :medium}
[quo/text {:weight :inherit}
(str (if amount
(wallet.utils/format-amount amount decimals)
"...")
" ")]
[quo/text {:color :secondary
:weight :inherit}
(wallet.utils/display-symbol token)]]
:subtitle (str (if value value "...") " " currency)
:accessibility-label (str (:symbol token) "-asset-value")
:icon (if icon
[wallet.components/token-icon icon]
[chat-icon/custom-icon-view-list (:name token) color])}])
@@ -5,24 +5,22 @@
[reagent.core :as reagent]
[status-im.i18n.i18n :as i18n]
[status-im.ui.screens.wallet.buy-crypto.views :as buy-crypto]
[status-im.ui.components.chat-icon.screen :as chat-icon]
[quo.design-system.colors :as colors]
[status-im.ui.components.icons.icons :as icons]
[status-im.ui.components.react :as react]
[status-im.ui.screens.wallet.accounts.sheets :as sheets]
[status-im.ui.screens.wallet.accounts.styles :as styles]
[status-im.qr-scanner.core :as qr-scanner]
[status-im.wallet.utils :as wallet.utils]
[status-im.keycard.login :as keycard.login]
[quo2.foundations.colors :as quo2.colors]
[quo2.components.button :as quo2.button]
[quo2.components.text :as quo2.text]
[quo2.components.tabs :as quo2.tabs]
[status-im.ui.screens.wallet.accounts.common :as common]
[status-im.ui.screens.wallet.account.views :as account.views]
[quo.components.safe-area :as safe-area])
[quo.react-native :as rn]
[status-im.utils.utils :as utils.utils]
[status-im.ui.screens.wallet.components.views :as wallet.components])
(:require-macros [status-im.utils.views :as views]))
(views/defview account-card [{:keys [name color address type wallet] :as account} keycard? card-width]
(views/letsubs [currency [:wallet/currency]
(views/letsubs [currency [:wallet/currency]
portfolio-value [:account-portfolio-value address]
prices-loading? [:prices-loading?]]
[react/touchable-highlight
@@ -37,7 +35,7 @@
[react/view {:style {:flex-direction :row}}
(if prices-loading?
[react/small-loading-indicator :colors/white-persist]
[react/text {:style styles/card-value
[react/text {:style styles/card-value
:accessibility-label "account-total-value"} portfolio-value])
[react/text {:style styles/card-value-currency} (str " " (:code currency))]]
(let [icon (cond
@@ -48,9 +46,9 @@
:main-icons/keycard-account)]
(when icon
[icons/icon icon {:container-style styles/card-icon-type
:color color}]))
:color color}]))
[react/touchable-highlight
{:style styles/card-icon-more
{:style styles/card-icon-more
:on-press #(re-frame/dispatch [:bottom-sheet/show-sheet
{:content (fn [] [sheets/account-card-actions account type wallet])
:content-height 130}])}
@@ -65,13 +63,30 @@
[icons/icon :main-icons/add-circle {:color colors/blue}]
[react/text {:style styles/add-text} (i18n/label :t/add-account)]]])
(defn render-asset [{:keys [icon decimals amount color value] :as token} _ _ currency]
[quo/list-item
{:title [quo/text {:weight :medium}
[quo/text {:weight :inherit}
(str (if amount
(wallet.utils/format-amount amount decimals)
"...")
" ")]
[quo/text {:color :secondary
:weight :inherit}
(wallet.utils/display-symbol token)]]
:subtitle (str (if value value "...") " " currency)
:accessibility-label (str (:symbol token) "-asset-value")
:icon (if icon
[wallet.components/token-icon icon]
[chat-icon/custom-icon-view-list (:name token) color])}])
(views/defview assets []
(views/letsubs [{:keys [tokens]} [:wallet/all-visible-assets-with-values]
currency [:wallet/currency]]
[:<>
(for [item tokens]
^{:key (:name item)}
[common/render-asset item nil nil (:code currency)])]))
[render-asset item nil nil (:code currency)])]))
(views/defview send-button []
(views/letsubs [account [:multiaccount/default-account]]
@@ -93,8 +108,7 @@
^{:key i}
[dot {:selected (= selected i)}])])
;;ACCOUNTS OLD
(views/defview accounts-old []
(views/defview accounts []
(views/letsubs [accounts [:multiaccount/visible-accounts]
keycard? [:keycard-multiaccount?]
window-width [:dimensions/window-width]
@@ -119,18 +133,17 @@
[account-card account keycard? card-width]))
[add-card card-width]]]
(let [columns (Math/ceil (/ (inc (count accounts)) 2))
totalwidth (* (styles/page-width card-width) columns)
totalwidth (* (styles/page-width card-width) columns)
n (Math/ceil (/ totalwidth window-width))]
(when (> n 1)
[dots-selector {:selected @index
:n n}]))])))
;;TOTAL VALUE OLD
(views/defview total-value-old [{:keys [animation minimized]}]
(views/letsubs [currency [:wallet/currency]
portfolio-value [:portfolio-value]
empty-balances? [:empty-balances?]
frozen-card? [:keycard/frozen-card?]
(views/defview total-value [{:keys [animation minimized]}]
(views/letsubs [currency [:wallet/currency]
portfolio-value [:portfolio-value]
empty-balances? [:empty-balances?]
frozen-card? [:keycard/frozen-card?]
{:keys [mnemonic]} [:multiaccount]]
[reanimated/view {:style (styles/container {:minimized minimized})}
(when (or
@@ -161,8 +174,8 @@
(i18n/label :t/your-card-is-frozen)
(i18n/label :t/back-up-your-seed-phrase))]]]])
[reanimated/view {:style (styles/value-container {:minimized minimized
:animation animation})
[reanimated/view {:style (styles/value-container {:minimized minimized
:animation animation})
:pointer-events :none}
[reanimated/view {:style {:justify-content :center}}
[quo/text {:animated? true
@@ -179,130 +192,39 @@
[quo/text {:color :secondary}
(i18n/label :t/wallet-total-value)]])]))
(views/defview total-value []
(views/letsubs [currency [:wallet/currency]
portfolio-value [:portfolio-value]]
;empty-balances? [:empty-balances?]
;frozen-card? [:keycard/frozen-card?]
;{:keys [mnemonic]} [:multiaccount]]
[react/view {:padding-vertical 12}
[quo2.text/text (i18n/label :t/wallet-total-value)]
[quo2.text/text {:size :heading-1 :weight :semi-bold}
(str portfolio-value " " (:code currency))]
[react/scroll-view {:horizontal true}]]
#_[reanimated/view {:style (styles/container {:minimized minimized})}
(when (or
(and frozen-card? minimized)
(and mnemonic minimized (not empty-balances?)))
[reanimated/view {:style (styles/accounts-mnemonic {:animation animation})}
[react/touchable-highlight
{:on-press #(re-frame/dispatch
(if frozen-card?
[::keycard.login/reset-pin]
[:navigate-to :backup-seed]))}
[react/view {:flex-direction :row
:align-items :center}
[react/view {:width 14
:height 14
:background-color colors/gray
:border-radius 7
:align-items :center
:justify-content :center
:margin-right 9}
[react/text {:style {:color colors/white
:font-size 13
:font-weight "700"}}
"!"]]
[react/text {:style {:color colors/gray}
:accessibility-label :back-up-your-seed-phrase-warning}
(if frozen-card?
(i18n/label :t/your-card-is-frozen)
(i18n/label :t/back-up-your-seed-phrase))]]]])
;; Note(rasom): sometimes `refreshing` might get stuck on iOS if action happened
;; too fast. By updating this atom in 1s we ensure that `refreshing?` property
;; is updated properly in this case.
(def updates-counter (reagent/atom 0))
[reanimated/view {:style (styles/value-container {:minimized minimized
:animation animation})
:pointer-events :none}
[reanimated/view {:style {:justify-content :center}}
[quo/text {:animated? true
:weight :semi-bold
:style (styles/value-text {:minimized minimized})}
portfolio-value
[quo/text {:animated? true
:size :inherit
:weight :inherit
:color :secondary}
(str " " (:code currency))]]]]
(when-not minimized
[reanimated/view
[quo/text {:color :secondary}
(i18n/label :t/wallet-total-value)]])]))
(defn schedule-counter-reset []
(utils.utils/set-timeout
(fn []
(swap! updates-counter inc)
(when @(re-frame/subscribe [:wallet/refreshing-history?])
(schedule-counter-reset)))
1000))
(views/defview accounts [selected-account-atom]
(views/letsubs [accounts [:multiaccount/visible-accounts]]
;keycard? [:keycard-multiaccount?]]
(do
(reset! selected-account-atom (:address (first accounts)))
(let [accounts-data (for [account accounts]
{:label (:name account)
:id (:address account)})]
[react/scroll-view {:horizontal true
:shows-horizontal-scroll-indicator false
:scroll-event-throttle 64
:margin-top 12
:margin-bottom 20}
[react/view {:flex-direction :row}
[quo2.tabs/tabs {:default-active (:address (first accounts))
:on-change #(reset! selected-account-atom %)
:data accounts-data}]
[quo2.button/button {:type :grey
:size 32
:on-press #(re-frame/dispatch [:bottom-sheet/show-sheet
{:content sheets/add-account
:content-height 260}])}
"Add account"]]]))))
(defn refresh-action []
(schedule-counter-reset)
(re-frame/dispatch [:wallet.ui/pull-to-refresh-history]))
(defn refresh-control [refreshing?]
(reagent/as-element
[rn/refresh-control
{:refreshing (boolean refreshing?)
:onRefresh refresh-action}]))
(defn accounts-overview []
(let [mnemonic @(re-frame/subscribe [:mnemonic])
;mainnet? @(re-frame/subscribe [:mainnet?])
selected-account-atom (reagent/atom nil)]
(fn []
[safe-area/consumer
(fn [insets]
[react/view {:style {:flex 1
:padding-top (:top insets)
:background-color (quo2.colors/theme-colors quo2.colors/neutral-5 quo2.colors/neutral-95)}}
[react/view {:padding-horizontal 20}
[react/view {:flex-direction :row :height 56 :align-items :center :justify-content :flex-end}
[quo2.button/button {:icon true
:size 32
:type :grey
:accessibility-label :accounts-qr-code
:on-press #(re-frame/dispatch
[::qr-scanner/scan-code
{:handler :wallet.send/qr-scanner-result}])}
:main-icons2/placeholder]
[react/view {:width 12}]
[quo2.button/button {:icon true
:size 32
:type :grey
:on-press #(re-frame/dispatch [:bottom-sheet/show-sheet
{:content (sheets/accounts-options mnemonic)}])
:accessibility-label :accounts-more-options}
:main-icons2/placeholder]]
[total-value]
[accounts selected-account-atom]]
[account.views/account-new @selected-account-atom]])])))
(defn accounts-overview-old []
(let [mnemonic @(re-frame/subscribe [:mnemonic])
mainnet? @(re-frame/subscribe [:mainnet?])]
[react/view
{:style {:flex 1}}
[quo/animated-header
{:extended-header total-value-old
:refresh-control common/refresh-control
{:extended-header total-value
:refresh-control refresh-control
:refreshing-sub (re-frame/subscribe [:wallet/refreshing-history?])
:refreshing-counter common/updates-counter
:refreshing-counter updates-counter
:use-insets true
:right-accessories [{:on-press #(re-frame/dispatch
[::qr-scanner/scan-code
@@ -313,9 +235,9 @@
{:content (sheets/accounts-options mnemonic)}])
:icon :main-icons/more
:accessibility-label :accounts-more-options}]}
[accounts-old]
[accounts]
(when mainnet?
[buy-crypto/banner])
[assets]
[react/view {:height 68}]]
[send-button]]))
[send-button]]))
@@ -8,10 +8,10 @@
(defn separator-dark []
[react/view (styles/separator-dark)])
(defn token-icon [{:keys [style source image-style width height]}]
(defn token-icon [{:keys [style source image-style]}]
[react/view {:style style}
[react/image {:source (if (fn? source) (source) source)
:style (merge
{:width (or width 40)
:height (or height 40)}
{:width 40
:height 40}
image-style)}]])
@@ -6,7 +6,7 @@
[quo.core :as quo]
[status-im.ui.components.chat-icon.screen :as chat-icon]
[status-im.ui.components.list.views :as list]
[status-im.ui.screens.wallet.accounts.common :as common]))
[status-im.ui.screens.wallet.accounts.views :as wallet.accounts]))
(views/defview assets [address]
(views/letsubs [{:keys [tokens]} [:wallet/visible-assets-with-values address]
@@ -15,7 +15,7 @@
(for [token tokens]
^{:key (str (:symbol token))}
[react/touchable-highlight {:on-press #(re-frame/dispatch [:wallet.send/set-symbol (:symbol token)])}
[common/render-asset token nil nil (:code currency)]])]))
[wallet.accounts/render-asset token nil nil (:code currency)]])]))
(defn render-account [account _ _ {:keys [field event]}]
[quo/list-item
+3 -3
View File
@@ -3,7 +3,7 @@
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
"owner": "status-im",
"repo": "status-go",
"version": "v0.98.5",
"commit-sha1": "640793fe85d9a9eef9eb3712cda1c5a1ceea401a",
"src-sha256": "1k1iw69yw23k29y0b1yvnggjqlmfnwavk4mq1sf2h3wrlb8x47kd"
"version": "v0.97.3",
"commit-sha1": "331cf1e40188553b508e81193d42e0eee6d6a8c8",
"src-sha256": "1yl7arvi6jlb591g6l2c4y41l5aqpvxcwl14iw73rp4qy4wvvcbz"
}
+2 -11
View File
@@ -7,12 +7,10 @@ import time
from json import JSONDecodeError
from decimal import Decimal
from os import environ
from web3.exceptions import TransactionNotFound
import tests
import support.api.web3_api as w3
class NetworkApi(object):
def __init__(self):
@@ -81,7 +79,7 @@ class NetworkApi(object):
counter = 0
while True:
if counter >= wait_time:
for entry in range(0, 5):
for entry in range(0,5):
self.log('Transaction #%s, amount is %s' %(entry+1, float(int(transactions[entry]['value']) / 10 ** decimals)))
self.log(str(transactions[entry]))
pytest.fail(
@@ -102,19 +100,12 @@ class NetworkApi(object):
try:
for transaction in transactions:
if float(int(transaction['value']) / 10 ** decimals) == float(amount):
self.log("Tx is found: %s (etherscan API)" % transaction['hash'])
try:
w3.transaction_status(transaction['hash'])
self.log("Tx is found (web3 API)")
except TransactionNotFound:
self.log("Tx is not found (web3 API)")
continue
return transaction
except TypeError as e:
self.log("Failed iterate transactions(Etherscan unexpected error): " + str(e))
continue
def wait_for_confirmation_of_transaction(self, address, amount, confirmations=3, token=False):
def wait_for_confirmation_of_transaction(self, address, amount, confirmations=6, token=False):
start_time = time.time()
if token:
token_info = "token transaction"
+2 -4
View File
@@ -48,8 +48,7 @@ class BaseTestReport:
'testrail_case_id': test.testrail_case_id,
'name': test.name,
'geth_paths': geth_paths,
'testruns': list(),
'group_name': test.group_name
'testruns': list()
}
for testrun in test.testruns:
test_dict['testruns'].append(testrun.__dict__)
@@ -71,8 +70,7 @@ class BaseTestReport:
tests.append(SingleTestData(name=test_data['name'],
geth_paths=test_data['geth_paths'],
testruns=testruns,
testrail_case_id=test_data['testrail_case_id'],
grop_name=test_data['group_name']))
testrail_case_id=test_data['testrail_case_id']))
return tests
def get_failed_tests(self):
+25 -50
View File
@@ -20,7 +20,6 @@ class GithubHtmlReport(BaseTestReport):
tests = self.get_all_tests()
passed_tests = self.get_passed_tests()
failed_tests = self.get_failed_tests()
not_executed_tests = TestrailReport().get_not_executed_tests(run_id)
if len(tests) > 0:
title_html = "## %.0f%% of end-end tests have passed\n" % (len(passed_tests) / len(tests) * 100)
@@ -28,18 +27,9 @@ class GithubHtmlReport(BaseTestReport):
summary_html += "Total executed tests: %d\n" % len(tests)
summary_html += "Failed tests: %d\n" % len(failed_tests)
summary_html += "Passed tests: %d\n" % len(passed_tests)
if not_executed_tests:
summary_html += "Not executed tests: %d\n" % len(not_executed_tests)
summary_html += "```\n"
not_executed_tests_html = str()
failed_tests_html = str()
passed_tests_html = str()
if not_executed_tests:
not_executed_tests_html = self.build_tests_table_html(not_executed_tests, run_id,
not_executed_tests=True)
summary_html += "```\n"
summary_html += 'IDs of not executed tests: %s \n' % ','.join([str(i) for i in not_executed_tests])
summary_html += "```\n"
if failed_tests:
failed_tests_html = self.build_tests_table_html(failed_tests, run_id, failed_tests=True)
summary_html += "```\n"
@@ -47,52 +37,39 @@ class GithubHtmlReport(BaseTestReport):
summary_html += "```\n"
if passed_tests:
passed_tests_html = self.build_tests_table_html(passed_tests, run_id, failed_tests=False)
return title_html + summary_html + not_executed_tests_html + failed_tests_html + passed_tests_html
return title_html + summary_html + failed_tests_html + passed_tests_html
else:
return None
def build_tests_table_html(self, tests, run_id, failed_tests=False, not_executed_tests=False):
if failed_tests:
tests_type = "Failed tests"
elif not_executed_tests:
tests_type = "Not executed tests"
else:
tests_type = "Passed tests"
def build_tests_table_html(self, tests, run_id, failed_tests=False):
tests_type = "Failed tests" if failed_tests else "Passed tests"
html = "<h3>%s (%d)</h3>" % (tests_type, len(tests))
html += "<details>"
html += "<summary>Click to expand</summary>"
html += "<br/>"
from tests import pytest_config_global
pr_id = pytest_config_global['pr_number']
apk_name = pytest_config_global['apk']
if not_executed_tests:
html += "<li><a href=\"%s\">Rerun not executed tests</a></li>" % self.get_jenkins_link_to_rerun_e2e(
pr_id=pr_id,
apk_name=apk_name,
tr_case_ids=','.join([str(i) for i in tests]))
if failed_tests:
html += "<li><a href=\"%s\">Rerun failed tests</a></li>" % self.get_jenkins_link_to_rerun_e2e(
pr_id=pr_id,
apk_name=apk_name,
tr_case_ids=','.join([str(test.testrail_case_id) for test in tests]))
from tests import pytest_config_global
pr_id = pytest_config_global['pr_number']
apk_name = pytest_config_global['apk']
tr_case_ids = self.list_of_failed_testrail_ids(self.get_failed_tests())
html += "<li><a href=\"%s\">Rerun tests</a></li>" % self.get_jenkins_link_to_rerun_e2e(pr_id=pr_id,
apk_name=apk_name,
tr_case_ids=tr_case_ids)
if not not_executed_tests:
html += "<br/>"
html += "<table style=\"width: 100%\">"
html += "<colgroup>"
html += "<col span=\"1\" style=\"width: 20%;\">"
html += "<col span=\"1\" style=\"width: 80%;\">"
html += "</colgroup>"
html += "<tbody>"
html += "<tr>"
html += "</tr>"
for i, test in enumerate(tests):
html += self.build_test_row_html(i, test, run_id)
html += "</tbody>"
html += "</table>"
html += "<br/>"
html += "<table style=\"width: 100%\">"
html += "<colgroup>"
html += "<col span=\"1\" style=\"width: 20%;\">"
html += "<col span=\"1\" style=\"width: 80%;\">"
html += "</colgroup>"
html += "<tbody>"
html += "<tr>"
html += "</tr>"
for i, test in enumerate(tests):
html += self.build_test_row_html(i, test, run_id)
html += "</tbody>"
html += "</table>"
html += "</details>"
return html
@@ -100,7 +77,7 @@ class GithubHtmlReport(BaseTestReport):
test_rail_link = TestrailReport().get_test_result_link(run_id, test.testrail_case_id)
if test_rail_link:
html = "<tr><td><b>%s. <a href=\"%s\">%s</a>, id: %s </b></td></tr>" % (
index + 1, test_rail_link, test.name, test.testrail_case_id)
index + 1, test_rail_link, test.name, test.testrail_case_id)
else:
html = "<tr><td><b>%d. %s</b> (TestRail link is not found)</td></tr>" % (index + 1, test.name)
html += "<tr><td>"
@@ -118,8 +95,6 @@ class GithubHtmlReport(BaseTestReport):
html += "</p>"
html += "<code>%s</code>" % last_testrun.error[:255]
html += "<br/><br/>"
if test.group_name:
html += "<p><b>Class: %s</b></p>" % test.group_name
if last_testrun.jobs:
html += self.build_device_sessions_html(last_testrun)
html += "</td></tr>"
@@ -142,4 +117,4 @@ class GithubHtmlReport(BaseTestReport):
html += "<li><a href=\"%s\">Failure screenshot</a></li>" % self.get_sauce_final_screenshot_url(job_id)
html += "</ul></p>"
html += "</ul></p>"
return html
return html
+3 -4
View File
@@ -2,12 +2,11 @@ from typing import Dict
class SingleTestData(object):
def __init__(self, name, testruns, testrail_case_id, geth_paths, grop_name):
def __init__(self, name, testruns, testrail_case_id, geth_paths):
self.testrail_case_id = testrail_case_id
self.name = name
self.testruns = testruns
self.geth_paths = geth_paths
self.group_name = grop_name
class TestRunData(object):
def __init__(self, steps, jobs, error, first_commands: Dict[str, int]):
@@ -31,6 +30,6 @@ class TestSuiteData(object):
if existing_test:
self.current_test = existing_test
else:
test = SingleTestData(test_name, list(), testrail_case_id, list(), None)
test = SingleTestData(test_name, list(), testrail_case_id, list())
self.tests.append(test)
self.current_test = test
self.current_test = test
+32 -63
View File
@@ -97,30 +97,23 @@ class TestrailReport(BaseTestReport):
def get_regression_cases(self):
test_cases = dict()
test_cases['pr'] = dict()
test_cases['nightly'] = dict()
test_cases['upgrade'] = dict()
## PR e2e
test_cases['pr']['critical'] = 730
test_cases['pr']['contacts'] = 50831
test_cases['pr']['public_chat'] = 50654
test_cases['pr']['one_to_one_chat'] = 50655
test_cases['pr']['group_chat'] = 50656
test_cases['pr']['onboarding'] = 50659
test_cases['pr']['recovery'] = 50660
test_cases['pr']['wallet'] = 50661
test_cases['pr']['send_tx'] = 50662
test_cases['pr']['keycard_tx'] = 50663
test_cases['pr']['1_1_chat_commands'] = 50825
test_cases['pr']['ens'] = 50827
test_cases['pr']['sync'] = 50834
## Nightly e2e
test_cases['nightly']['medium'] = 736
test_cases['nightly']['chat'] = 50811
test_cases['nightly']['browser'] = 50826
test_cases['nightly']['profile'] = 50828
## Upgrade e2e
test_cases['upgrade']['general'] = 881
test_cases['critical'] = 730
test_cases['medium'] = 736
test_cases['upgrade'] = 881
## tests pr
test_cases['public_chat'] = 50654
test_cases['one_to_one_chat'] = 50655
test_cases['group_chat'] = 50656
test_cases['onboarding'] = 50659
test_cases['recovery'] = 50660
test_cases['wallet'] = 50661
test_cases['send_tx'] = 50662
test_cases['keycard_tx'] = 50663
test_cases['browser'] = 50812
test_pr = list()
for key in test_cases:
if key != 'medium' and key != 'upgrade':
test_pr.append(test_cases[key])
case_ids = list()
for arg in argv:
@@ -128,21 +121,17 @@ class TestrailReport(BaseTestReport):
key, value = arg.split('=')
case_ids = value.split(',')
if len(case_ids) == 0:
if 'critical' in argv:
for category in test_cases['pr']:
for case in self.get_cases([test_cases['pr'][category]]):
case_ids.append(case['id'])
if 'critical or high' in argv:
for case in self.get_cases(test_pr):
case_ids.append(case['id'])
elif 'upgrade' in argv and 'not upgrade' not in argv:
for case in self.get_cases([test_cases['upgrade']['general']]):
for case in self.get_cases([test_cases['upgrade']]):
case_ids.append(case['id'])
else:
for phase in test_cases:
if phase != 'upgrade':
print("For %s phase" % phase)
for category in test_cases[phase]:
print("For %s category" % category)
for case in self.get_cases([test_cases[phase][category]]):
case_ids.append(case['id'])
for case in self.get_cases([test_cases[phase]]):
case_ids.append(case['id'])
return case_ids
def add_results(self):
@@ -159,21 +148,14 @@ class TestrailReport(BaseTestReport):
i + 1, self.get_sauce_job_url(job_id=device, first_command=last_testrun.first_commands[device]))
else:
devices += "# [Device %d](%s) \n" % (i + 1, self.get_sauce_job_url(job_id=device))
comment = str()
if test.group_name:
comment += "# Class: %s \n" % test.group_name
if last_testrun.error:
comment += '%s' % ('# Error: \n %s \n' % emoji.demojize(last_testrun.error)) + devices + test_steps
else:
comment += devices + test_steps
data = {'status_id': self.outcomes['undefined_fail'] if last_testrun.error else self.outcomes['passed'],
'comment': comment}
result = self.post(method, data=data)
'comment': '%s' % ('# Error: \n %s \n' % emoji.demojize(
last_testrun.error)) + devices + test_steps if last_testrun.error
else devices + test_steps}
try:
result_id = result['id']
result_id = self.post(method, data=data)['id']
except KeyError:
result_id = ''
print("Got TestRail error when adding results for case %s: \n%s" % (test.testrail_case_id, result))
if last_testrun.error:
try:
for geth in test.geth_paths.keys():
@@ -187,7 +169,6 @@ class TestrailReport(BaseTestReport):
tests = self.get_all_tests()
passed_tests = self.get_passed_tests()
failed_tests = self.get_failed_tests()
not_executed_tests = self.get_not_executed_tests(self.run_id)
final_description = "Nothing to report this time..."
if len(tests) > 0:
description_title = "# %.0f%% of end-end tests have passed\n" % (len(passed_tests) / len(tests) * 100)
@@ -195,8 +176,6 @@ class TestrailReport(BaseTestReport):
description_title += "Total executed tests: %d\n" % len(tests)
description_title += "Failed tests: %d\n" % len(failed_tests)
description_title += "Passed tests: %d\n" % len(passed_tests)
if not_executed_tests:
description_title += "Not executed tests: %d\n" % len(not_executed_tests)
description_title += "\n"
ids_failed_test = []
description, case_info = '', ''
@@ -208,7 +187,7 @@ class TestrailReport(BaseTestReport):
case_title = '\n'
case_title += '-------\n'
case_title += "## %s) ID %s: [%s](%s) \n" % (
i + 1, test.testrail_case_id, test.name, test_rail_link)
i + 1, test.testrail_case_id, test.name, test_rail_link)
error = "```%s```\n" % last_testrun.error[:255]
for job_id, f in last_testrun.jobs.items():
if last_testrun.first_commands:
@@ -219,21 +198,15 @@ class TestrailReport(BaseTestReport):
case_info = "Logs for device %d: [steps](%s), [failure screenshot](%s)" \
% (f, job_url, self.get_sauce_final_screenshot_url(job_id))
if test.group_name:
class_name = "Class: %s\n" % test.group_name
description += case_title + class_name + error + case_info
else:
description += case_title + error + case_info
description += case_title + error + case_info
description_title += '## Failed tests: %s \n' % ','.join(map(str, ids_failed_test))
if not_executed_tests:
description_title += "## Not executed tests: %s\n" % ','.join([str(i) for i in not_executed_tests])
final_description = description_title + description
request_body = {'description': final_description}
return self.post('update_run/%s' % self.run_id, request_body)
def get_run_results(self, test_run_id=None):
return self.get('get_results_for_run/%s' % (test_run_id if test_run_id else self.run_id))['results']
def get_run_results(self):
return self.get('get_results_for_run/%s' % self.run_id)['results']
def is_run_successful(self):
for test in self.get_run_results():
@@ -247,8 +220,4 @@ class TestrailReport(BaseTestReport):
test_id = self.get('get_results_for_case/%s/%s' % (test_run_id, test_case_id))['results'][0]['test_id']
return '%stests/view/%s' % (self.url, test_id)
except KeyError:
return None
def get_not_executed_tests(self, test_run_id):
results = self.get("get_tests/%s&status_id=3" % test_run_id)
return [result['case_id'] for result in results["tests"]]
return None
+1 -8
View File
@@ -6,15 +6,8 @@ import json
from support.appium_container import AppiumContainer
from support.test_data import TestSuiteData
import time
async def start_threads(quantity: int, func: type, returns: dict, *args):
loop = asyncio.get_event_loop()
from tests.conftest import sauce
for _ in range(60):
if 16 - len([job for job in sauce.jobs.get_jobs() if job['status'] == 'in progress']) < quantity:
time.sleep(10)
for i in range(quantity):
returns[i] = loop.run_in_executor(None, func, *args)
for k in returns:
@@ -35,7 +28,7 @@ pytest_config_global = dict()
test_suite_data = TestSuiteData()
appium_container = AppiumContainer()
common_password = 'qwerty'
common_password = 'qwerty1234'
unique_password = 'unique' + get_current_time()
pin = '121212'
puk = '000000000000'
@@ -2,15 +2,14 @@ import random
import pytest
from support.utilities import fill_string_with_char
from tests import marks, common_password
from tests.base_test_case import MultipleSharedDeviceTestCase, create_shared_drivers
from tests import marks, common_password, unique_password
from tests.base_test_case import SingleDeviceTestCase, MultipleSharedDeviceTestCase, create_shared_drivers
from views.sign_in_view import SignInView
from tests.users import basic_user, transaction_senders
from tests.users import basic_user, transaction_senders, recovery_users
@pytest.mark.xdist_group(name="onboarding_1")
@marks.critical
@pytest.mark.run2
class TestOnboardingOneDeviceMerged(MultipleSharedDeviceTestCase):
@classmethod
@@ -85,7 +84,7 @@ class TestOnboardingOneDeviceMerged(MultipleSharedDeviceTestCase):
wallet.click_system_back_button()
self.home.just_fyi("Check that can paste wallet address in chat message input")
wallet.home_button.double_click()
wallet.home_button.click()
self.home.get_chat('#%s' % self.public_chat_name).click()
self.chat.chat_message_input.click()
self.chat.paste_text()
@@ -188,14 +187,14 @@ class TestOnboardingOneDeviceMerged(MultipleSharedDeviceTestCase):
error = "Can create multiaccount when"
self.sign_in.just_fyi('Checking case when %s' % cases[0])
self.sign_in.create_password_input.send_keys('123456')
self.sign_in.create_password_input.send_keys('12345677')
self.sign_in.next_button.click()
if self.sign_in.maybe_later_button.is_element_displayed(10):
self.driver.fail('%s %s' % (error, cases[0]))
self.sign_in.just_fyi('Checking case when %s' % cases[1])
self.sign_in.create_password_input.send_keys('123456')
[field.send_keys('123456') for field in (self.sign_in.create_password_input, self.sign_in.confirm_your_password_input)]
self.sign_in.create_password_input.send_keys('12345677')
[field.send_keys('12345677') for field in (self.sign_in.create_password_input, self.sign_in.confirm_your_password_input)]
self.sign_in.confirm_your_password_input.delete_last_symbols(1)
self.sign_in.create_password_input.delete_last_symbols(1)
self.sign_in.next_button.click()
@@ -203,8 +202,8 @@ class TestOnboardingOneDeviceMerged(MultipleSharedDeviceTestCase):
self.driver.fail('%s %s' % (error, cases[1]))
self.sign_in.just_fyi("Checking case %s" % cases[2])
self.sign_in.create_password_input.send_keys('1234565')
self.sign_in.confirm_your_password_input.send_keys('1234567')
self.sign_in.create_password_input.send_keys('12345654')
self.sign_in.confirm_your_password_input.send_keys('12345677')
if not self.sign_in.element_by_translation_id("password_error1").is_element_displayed():
self.errors.append("'%s' is not shown" % self.sign_in.get_translation_by_key("password_error1"))
self.sign_in.create_password_input.set_value(common_password)
@@ -214,8 +213,8 @@ class TestOnboardingOneDeviceMerged(MultipleSharedDeviceTestCase):
[element.wait_and_click(10) for element in (self.sign_in.maybe_later_button, self.sign_in.lets_go_button)]
self.home.cross_icon_inside_welcome_screen_button.wait_and_click(10)
if not self.home.element_by_translation_id("welcome-blank-message").is_element_displayed():
self.errors.append("'%s' text is not shown after welcome view was closed" %
self.home.get_translation_by_key("welcome-blank-message"))
self.errors.append("'%s' text is not shown after welcome view was closed" % self.home.get_translation_by_key(
"welcome-blank-message"))
self.home.profile_button.click()
shown_username = self.profile.default_username_text.text
if shown_username != username:
@@ -225,11 +224,10 @@ class TestOnboardingOneDeviceMerged(MultipleSharedDeviceTestCase):
@pytest.mark.xdist_group(name="restore_1")
@marks.critical
@pytest.mark.run2
class TestRestoreOneDeviceMerged(MultipleSharedDeviceTestCase):
@classmethod
def setup_class(cls):
cls.user = transaction_senders['ETH_ADI_STT_2']
cls.user = transaction_senders['A']
cls.drivers, cls.loop = create_shared_drivers(1)
cls.sign_in = SignInView(cls.drivers[0])
cls.passphrase = fill_string_with_char(cls.user['passphrase'].upper(), ' ', 3, True, True)
@@ -304,7 +302,7 @@ class TestRestoreOneDeviceMerged(MultipleSharedDeviceTestCase):
self.errors.verify_no_errors()
@marks.testrail_id(700750)
def test_restore_seed_phrase_field_validation(self):
def test_restore_validation_seed_phrase_field(self):
validations = [
{
'case': 'empty value',
@@ -328,8 +326,8 @@ class TestRestoreOneDeviceMerged(MultipleSharedDeviceTestCase):
'popup': True
},
]
self.home.driver.close_app()
self.home.driver.launch_app()
profile = self.home.profile_button.click()
profile.logout()
if self.sign_in.ok_button.is_element_displayed():
self.sign_in.ok_button.click()
self.sign_in.back_button.click()
@@ -342,7 +340,8 @@ class TestRestoreOneDeviceMerged(MultipleSharedDeviceTestCase):
self.errors.append("Possible to create account with empty seed phrase")
for validation in validations:
self.sign_in.just_fyi("Checking %s" % validation.get('case'))
phrase, msg, words_count, popup = validation.get('phrase'), validation.get('validation message'), \
phrase, msg, words_count, popup = validation.get('phrase'), \
validation.get('validation message'), \
validation.get('words count'), \
validation.get('popup')
if self.sign_in.access_key_button.is_element_displayed():
@@ -377,105 +376,23 @@ class TestRestoreOneDeviceMerged(MultipleSharedDeviceTestCase):
self.sign_in.click_system_back_button()
self.errors.verify_no_errors()
@marks.testrail_id(702189)
def test_restore_account_migrate_multiaccount_to_keycard_no_db_saved_add_wallet_send_tx(self):
self.sign_in.driver.close_app()
self.sign_in.driver.launch_app()
self.sign_in.sign_in(password=self.password)
self.home.home_button.wait_for_visibility_of_element(30)
profile = self.home.profile_button.click()
profile.profile_button.double_click()
profile.privacy_and_security_button.click()
profile.element_by_translation_id("manage-keys-and-storage").scroll_and_click()
profile.logout_dialog.logout_button.wait_and_click()
profile.logout_button.wait_for_invisibility_of_element(30)
if not self.sign_in.element_by_translation_id("move-keystore-file").is_element_displayed():
self.errors.append("Was not redirected to Key management screen when Manage keys from logged in state!")
self.home.just_fyi("Checking keycard banner and starting migrate multiaccount to keycard: no db saved")
self.sign_in.close_button.click()
self.sign_in.back_button.click()
self.sign_in.multi_account_on_login_button.wait_for_visibility_of_element(30)
self.sign_in.get_multiaccount_by_position(1).click()
if not self.sign_in.get_keycard_banner.is_element_displayed():
self.errors.append("Get a keycard banner is not shown on login screen for ordinary multiaccount")
self.sign_in.options_button.click()
self.sign_in.manage_keys_and_storage_button.click()
if not self.sign_in.element_by_text(self.user['username']).is_element_displayed():
self.driver.fail("Default username is not shown when migrating multiaccount to keycard!")
class TestCreateAccount(SingleDeviceTestCase):
self.home.just_fyi("Checking validation of seed phrase during migration")
self.sign_in.enter_seed_phrase_next_button.click()
if self.sign_in.seedphrase_input.is_element_displayed():
self.sign_in.driver.fail("Proceeded to seedphrase input without confirmed Actions")
self.sign_in.move_keystore_file_option.click()
self.sign_in.reset_database_checkbox.click()
self.sign_in.enter_seed_phrase_next_button.click()
self.sign_in.seedphrase_input.set_value(transaction_senders['A']['passphrase'])
self.sign_in.choose_storage_button.click()
if not self.sign_in.element_by_translation_id("seed-key-uid-mismatch").is_element_displayed():
self.driver.fail("Can proceed with seed phrase of another user")
self.sign_in.element_by_translation_id("try-again").click()
self.sign_in.seedphrase_input.set_value(self.user['passphrase'][:-1])
self.sign_in.choose_storage_button.click()
if not self.sign_in.custom_seed_phrase_label.is_element_displayed():
self.driver.fail("Can proceed with invalid seed phrase")
self.sign_in.cancel_button.click()
self.sign_in.seedphrase_input.set_value(self.user['passphrase'])
self.sign_in.choose_storage_button.click()
if not self.sign_in.get_keycard_banner.is_element_displayed():
self.errors.append("Get a keycard banner is not shown on Key management screen")
self.sign_in.keycard_required_option.click()
if self.sign_in.get_keycard_banner.is_element_displayed():
self.errors.append("Get a keycard banner is shown when keycard storage is chosen")
self.sign_in.just_fyi("Finishing migration to keycard")
self.sign_in.confirm_button.click()
keycard = self.sign_in.move_and_reset_button.click()
keycard.begin_setup_button.click()
keycard.connect_card_button.wait_and_click()
keycard.enter_default_pin()
keycard.enter_default_pin()
if not self.sign_in.element_by_translation_id("migration-successful").is_element_displayed(30):
self.driver.fail("No popup about successfull migration is shown!")
self.sign_in.ok_button.click()
self.sign_in.maybe_later_button.wait_and_click(30)
self.sign_in.lets_go_button.wait_and_click(30)
self.sign_in.just_fyi('Check that after migrating account with assets is restored')
wallet = self.sign_in.wallet_button.click()
for asset in ['ETH', 'ADI', 'STT']:
if wallet.get_asset_amount_by_name(asset) == 0:
self.errors.append('Asset %s was not restored' % asset)
self.sign_in.just_fyi('Check that after migration wallet address matches expected')
address = wallet.get_wallet_address()
if address != '0x%s' % self.user['address']:
self.errors.append('Restored address %s does not match expected' % address)
self.sign_in.just_fyi('Check that after migration username and public key match expected')
public_key, default_username = self.sign_in.get_public_key_and_username(return_username=True)
profile = self.sign_in.get_profile_view()
if public_key != self.user['public_key']:
self.errors.append('Public key %s does not match expected' % public_key)
if default_username != self.user['username']:
self.errors.append('Default username %s does not match expected' % default_username)
profile.logout()
self.sign_in.just_fyi(
'Check that can login with migrated account, keycard banner is not shown and no option to migrate')
self.sign_in.get_multiaccount_by_position(1).click()
if self.sign_in.get_keycard_banner.is_element_displayed():
self.errors.append("Get a keycard banner is shown on migrated keycard multiaccount")
keycard.one_button.wait_for_visibility_of_element(10)
keycard.enter_default_pin()
if not self.sign_in.home_button.is_element_displayed(30):
self.driver.fail('Keycard user is not logged in')
self.sign_in.just_fyi('Check that can add another wallet account and send transaction')
self.home.wallet_button.click()
wallet.add_account(account_name="another_keycard_account", keycard=True)
transaction_amount_added = wallet.get_unique_amount()
wallet.send_transaction(amount=transaction_amount_added, recipient=transaction_senders['ETH_8']['address'],
keycard=True, sign_transaction=True)
@marks.testrail_id(5455)
@marks.medium
def test_recover_accounts_with_certain_seedphrase(self):
sign_in = SignInView(self.driver)
for phrase, account in recovery_users.items():
home_view = sign_in.recover_access(passphrase=phrase, password=unique_password)
wallet_view = home_view.wallet_button.click()
address = wallet_view.get_wallet_address()
if address != account:
self.errors.append('Restored wallet address "%s" does not match expected "%s"' % (address, account))
profile = home_view.profile_button.click()
profile.privacy_and_security_button.click()
profile.delete_my_profile_button.scroll_and_click()
profile.delete_my_profile_password_input.set_value(unique_password)
profile.delete_profile_button.click()
profile.ok_button.click()
self.errors.verify_no_errors()
@@ -0,0 +1,590 @@
from tests import marks, pair_code, common_password
from tests.base_test_case import SingleDeviceTestCase, MultipleDeviceTestCase
from views.sign_in_view import SignInView
from tests.users import basic_user, transaction_senders
class TestCreateAccount(SingleDeviceTestCase):
@marks.testrail_id(6645)
@marks.critical
def test_restore_account_migrate_multiaccount_to_keycard(self):
sign_in = SignInView(self.driver)
user = transaction_senders['ETH_ADI_STT_2']
seed = user['passphrase']
home = sign_in.recover_access(passphrase=seed)
profile = home.profile_button.click()
profile.privacy_and_security_button.click()
profile.element_by_translation_id("manage-keys-and-storage").scroll_and_click()
profile.logout_dialog.logout_button.wait_and_click()
profile.logout_button.wait_for_invisibility_of_element(30)
if not sign_in.element_by_translation_id("move-keystore-file").is_element_displayed():
self.errors.append("Was not redirected to Key management screen when Manage keys from logged in state!")
home.just_fyi("Checking keycard banner and starting migrate multiaccount to keycard: no db saved")
sign_in.close_button.click()
sign_in.back_button.click()
sign_in.multi_account_on_login_button.wait_for_visibility_of_element(30)
sign_in.get_multiaccount_by_position(1).click()
if not sign_in.get_keycard_banner.is_element_displayed():
self.errors.append("Get a keycard banner is not shown on login screen for ordinary multiaccount")
sign_in.options_button.click()
sign_in.manage_keys_and_storage_button.click()
if not sign_in.element_by_text(user['username']).is_element_displayed():
self.driver.fail("Default username is not shown when migrating multiaccount to keycard!")
home.just_fyi("Checking validation of seed phrase during migration")
sign_in.enter_seed_phrase_next_button.click()
if sign_in.seedphrase_input.is_element_displayed():
self.driver.fail("Proceeded to seedphrase input without confirmed Actions")
sign_in.move_keystore_file_option.click()
sign_in.reset_database_checkbox.click()
sign_in.enter_seed_phrase_next_button.click()
sign_in.seedphrase_input.set_value(transaction_senders['A']['passphrase'])
sign_in.choose_storage_button.click()
if not sign_in.element_by_translation_id("seed-key-uid-mismatch").is_element_displayed():
self.driver.fail("Can proceed with seed phrase of another user")
sign_in.element_by_translation_id("try-again").click()
sign_in.seedphrase_input.set_value(seed[:-1])
sign_in.choose_storage_button.click()
if not sign_in.custom_seed_phrase_label.is_element_displayed():
self.driver.fail("Can proceed with invalid seed phrase")
sign_in.cancel_button.click()
sign_in.seedphrase_input.set_value(seed)
sign_in.choose_storage_button.click()
if not sign_in.get_keycard_banner.is_element_displayed():
self.errors.append("Get a keycard banner is not shown on Key management screen")
sign_in.keycard_required_option.click()
if sign_in.get_keycard_banner.is_element_displayed():
self.errors.append("Get a keycard banner is shown when keycard storage is chosen")
home.just_fyi("Finishing migration to keycard")
sign_in.confirm_button.click()
keycard = sign_in.move_and_reset_button.click()
keycard.begin_setup_button.click()
keycard.connect_card_button.wait_and_click()
keycard.enter_default_pin()
keycard.enter_default_pin()
if not sign_in.element_by_translation_id("migration-successful").is_element_displayed(30):
self.driver.fail("No popup about successfull migration is shown!")
sign_in.ok_button.click()
sign_in.maybe_later_button.wait_and_click(30)
sign_in.lets_go_button.wait_and_click(30)
sign_in.just_fyi('Check that after migrating account with assets is restored')
wallet = sign_in.wallet_button.click()
for asset in ['ETH', 'ADI', 'STT']:
if wallet.get_asset_amount_by_name(asset) == 0:
self.errors.append('Asset %s was not restored' % asset)
sign_in.just_fyi('Check that after migration wallet address matches expected')
address = wallet.get_wallet_address()
if address != '0x%s' % user['address']:
self.errors.append('Restored address %s does not match expected' % address)
sign_in.just_fyi('Check that after migration username and public key match expected')
public_key, default_username = sign_in.get_public_key_and_username(return_username=True)
profile = sign_in.get_profile_view()
if public_key != user['public_key']:
self.errors.append('Public key %s does not match expected' % public_key)
if default_username != user['username']:
self.errors.append('Default username %s does not match expected' % default_username)
profile.logout()
sign_in.just_fyi(
'Check that can login with migrated account, keycard banner is not shown and no option to migrate')
sign_in.get_multiaccount_by_position(1).click()
if sign_in.get_keycard_banner.is_element_displayed():
self.errors.append("Get a keycard banner is shown on migrated keycard multiaccount")
keycard.one_button.wait_for_visibility_of_element(10)
keycard.enter_default_pin()
if not sign_in.home_button.is_element_displayed(30):
self.driver.fail('Keycard user is not logged in')
sign_in.just_fyi('Check that can add another wallet account and send transaction')
home.wallet_button.click()
wallet.add_account(account_name="another_keycard_account", keycard=True)
transaction_amount_added = wallet.get_unique_amount()
wallet.send_transaction(amount=transaction_amount_added, recipient=transaction_senders['ETH_8']['address'],
keycard=True, sign_transaction=True)
self.driver.reset()
home = sign_in.recover_access(passphrase=seed)
contact, nickname, message = transaction_senders['A'], 'my_friend', 'some message'
chat = home.add_contact(contact['public_key'], nickname=nickname)
chat.send_message(message)
profile = home.profile_button.click()
profile.logout()
home.just_fyi("Checking migration to keycard: db saved (1-1 chat, nickname, messages)")
sign_in.options_button.click()
sign_in.manage_keys_and_storage_button.click()
sign_in.move_keystore_file_option.click()
sign_in.enter_seed_phrase_next_button.click()
sign_in.seedphrase_input.set_value(seed)
sign_in.choose_storage_button.click()
sign_in.keycard_required_option.click()
sign_in.confirm_button.click()
sign_in.migration_password_input.set_value(common_password)
sign_in.confirm_button.click()
keycard.begin_setup_button.click()
keycard.connect_card_button.wait_and_click()
keycard.enter_default_pin()
keycard.enter_default_pin()
if not sign_in.element_by_translation_id("migration-successful").is_element_displayed(30):
self.driver.fail("No popup about successfull migration is shown!")
sign_in.ok_button.click()
home.home_button.wait_for_element(30)
home.get_chat(nickname).click()
if chat.add_to_contacts.is_element_displayed():
self.errors.append("User was removed from contacts after migration to kk")
if not chat.chat_element_by_text(message).is_element_displayed():
self.errors.append("Message from 1-1 was removed from contacts after migration to kk")
self.errors.verify_no_errors()
@marks.testrail_id(5742)
@marks.medium
def test_keycard_interruption_creating_onboarding_flow(self):
sign_in = SignInView(self.driver)
sign_in.just_fyi('Cancel on PIN code setup stage')
sign_in.accept_tos_checkbox.enable()
sign_in.get_started_button.click()
sign_in.generate_key_button.click()
username = sign_in.first_username_on_choose_chat_name.text
sign_in.next_button.click()
keycard_flow = sign_in.keycard_storage_button.click()
keycard_flow.next_button.click()
keycard_flow.begin_setup_button.click()
keycard_flow.connect_card_button.wait_and_click()
keycard_flow.enter_another_pin()
keycard_flow.cancel_button.click()
sign_in.just_fyi('Cancel from Confirm seed phrase: initialized + 1 pairing slot is used')
keycard_flow.begin_setup_button.click()
keycard_flow.enter_default_pin()
keycard_flow.enter_default_pin()
seed_phrase = keycard_flow.get_seed_phrase()
keycard_flow.confirm_button.click()
keycard_flow.yes_button.click()
keycard_flow.cancel_button.click()
if not keycard_flow.element_by_text_part('Back up seed phrase').is_element_displayed():
self.driver.fail('On canceling setup from Confirm seed phrase was not redirected to expected screen')
sign_in.just_fyi('Cancel from Back Up seed phrase: initialized + 1 pairing slot is used')
keycard_flow.cancel_button.click()
keycard_flow.begin_setup_button.click()
keycard_flow.element_by_translation_id("back-up-seed-phrase").wait_for_element(10)
new_seed_phrase = keycard_flow.get_seed_phrase()
if new_seed_phrase != seed_phrase:
self.errors.append('Another seed phrase is shown after cancelling setup during Back up seed phrase')
keycard_flow.backup_seed_phrase()
keycard_flow.enter_default_pin()
for element in sign_in.maybe_later_button, sign_in.lets_go_button:
element.wait_for_visibility_of_element(30)
element.click()
sign_in.profile_button.wait_for_visibility_of_element(30)
sign_in.just_fyi('Check username and relogin')
profile = sign_in.get_profile_view()
public_key, real_username = profile.get_public_key_and_username(return_username=True)
if real_username != username:
self.errors.append('Username was changed after interruption of creating account')
profile.logout()
home = sign_in.sign_in(keycard=True)
if not home.wallet_button.is_element_displayed(10):
self.errors.append("Failed to login to Keycard account")
self.errors.verify_no_errors()
@marks.testrail_id(6246)
@marks.medium
@marks.flaky
def test_keycard_interruption_access_key_onboarding_flow(self):
sign_in = SignInView(self.driver)
sign_in.accept_tos_checkbox.enable()
sign_in.get_started_button.click()
sign_in.access_key_button.click()
sign_in.enter_seed_phrase_button.click()
sign_in.seedphrase_input.click()
sign_in.seedphrase_input.set_value(basic_user['passphrase'])
sign_in.next_button.click()
sign_in.reencrypt_your_key_button.click()
keycard_flow = sign_in.keycard_storage_button.click()
sign_in.just_fyi('Cancel on PIN code setup stage')
keycard_flow.next_button.click()
keycard_flow.begin_setup_button.click()
keycard_flow.connect_card_button.wait_and_click()
keycard_flow.enter_another_pin()
keycard_flow.cancel_button.click()
sign_in.just_fyi('Finish setup and relogin')
keycard_flow.begin_setup_button.click()
keycard_flow.enter_default_pin()
keycard_flow.enter_default_pin()
for element in sign_in.maybe_later_button, sign_in.lets_go_button:
element.wait_for_visibility_of_element(30)
element.click()
sign_in.profile_button.wait_for_visibility_of_element(30)
public_key, default_username = sign_in.get_public_key_and_username(return_username=True)
profile_view = sign_in.get_profile_view()
if public_key != basic_user['public_key']:
self.errors.append('Public key %s does not match expected' % public_key)
if default_username != basic_user['username']:
self.errors.append('Default username %s does not match expected' % default_username)
profile_view.logout()
home = sign_in.sign_in(keycard=True)
if not home.wallet_button.is_element_displayed(10):
self.errors.append("Failed to login to Keycard account")
self.errors.verify_no_errors()
@marks.testrail_id(6243)
@marks.medium
def test_keycard_can_recover_keycard_account_offline_and_add_watch_only_acc(self):
sign_in = SignInView(self.driver)
sign_in.toggle_airplane_mode()
sign_in.just_fyi('Recover multiaccount offline')
sign_in.accept_tos_checkbox.enable()
sign_in.get_started_button.click_until_presence_of_element(sign_in.access_key_button)
sign_in.access_key_button.click()
sign_in.recover_with_keycard_button.click()
keycard_view = sign_in.begin_recovery_button.click()
keycard_view.connect_pairing_card_button.click()
keycard_view.pair_code_input.set_value(pair_code)
keycard_view.confirm()
keycard_view.enter_default_pin()
sign_in.maybe_later_button.click_until_presence_of_element(sign_in.lets_go_button)
sign_in.lets_go_button.click_until_absense_of_element(sign_in.lets_go_button)
sign_in.home_button.wait_for_visibility_of_element(30)
wallet_view = sign_in.wallet_button.click()
sign_in.just_fyi('Relogin offline')
self.driver.close_app()
self.driver.launch_app()
sign_in.sign_in(keycard=True)
if not sign_in.home_button.is_element_displayed(10):
self.driver.fail('Keycard user is not logged in')
sign_in.just_fyi('Turn off airplane mode and turn on cellular network')
sign_in.toggle_airplane_mode()
sign_in.toggle_mobile_data()
sign_in.element_by_text_part('Stop syncing').wait_and_click(60)
sign_in.wallet_button.click()
if not wallet_view.element_by_text_part('LXS').is_element_displayed():
self.errors.append('Token balance is not fetched while on cellular network!')
wallet_view.just_fyi('Add watch-only account when on cellular network')
wallet_view.add_account_button.click()
wallet_view.add_watch_only_address_button.click()
wallet_view.enter_address_input.send_keys(basic_user['address'])
account_name = 'watch-only'
wallet_view.account_name_input.send_keys(account_name)
wallet_view.add_account_generate_account_button.click()
account_button = wallet_view.get_account_by_name(account_name)
if not account_button.is_element_displayed():
self.driver.fail('Account was not added')
wallet_view.just_fyi('Check that balance is changed after go back to WI-FI')
sign_in.toggle_mobile_data()
for asset in ('ADI', 'STT'):
wallet_view.asset_by_name(asset).scroll_to_element()
wallet_view.wait_balance_is_changed(asset, wait_time=60)
wallet_view.just_fyi('Delete watch-only account')
wallet_view.get_account_by_name(account_name).click()
wallet_view.get_account_options_by_name(account_name).click()
wallet_view.account_settings_button.click()
wallet_view.delete_account_button.click()
wallet_view.yes_button.click()
if wallet_view.get_account_by_name(account_name).is_element_displayed(20):
self.errors.append('Account was not deleted')
self.errors.verify_no_errors()
@marks.testrail_id(6311)
@marks.medium
@marks.transaction
def test_same_seed_added_inside_multiaccount_and_keycard(self):
sign_in = SignInView(self.driver)
recipient = "0x" + transaction_senders['ETH_7']['address']
user = transaction_senders['ETH_ADI_STT_3']
sign_in.just_fyi('Restore keycard multiaccount and logout')
sign_in.recover_access(passphrase=user['passphrase'], keycard=True)
profile_view = sign_in.profile_button.click()
profile_view.logout()
sign_in.just_fyi('Create new multiaccount')
sign_in.close_button.click()
sign_in.your_keys_more_icon.click()
sign_in.generate_new_key_button.click()
sign_in.next_button.click()
sign_in.next_button.click()
sign_in.create_password_input.set_value(common_password)
sign_in.next_button.click()
sign_in.confirm_your_password_input.set_value(common_password)
sign_in.next_button.click()
sign_in.maybe_later_button.click_until_presence_of_element(sign_in.lets_go_button)
sign_in.lets_go_button.click()
sign_in.just_fyi('Add to wallet seed phrase for restored multiaccount')
wallet = sign_in.wallet_button.click()
wallet.add_account_button.click()
wallet.enter_a_seed_phrase_button.click()
wallet.enter_your_password_input.send_keys(common_password)
account_name = 'subacc'
wallet.account_name_input.send_keys(account_name)
wallet.enter_seed_phrase_input.set_value(user['passphrase'])
wallet.add_account_generate_account_button.click()
wallet.get_account_by_name(account_name).click()
sign_in.just_fyi('Send transaction from added account and log out')
transaction_amount_added = wallet.get_unique_amount()
wallet.send_transaction(from_main_wallet=False, amount=transaction_amount_added, recipient=recipient,
sign_transaction=True)
wallet.profile_button.click()
profile_view.logout()
sign_in.just_fyi('Login to keycard account and send another transaction')
sign_in.back_button.click()
sign_in.sign_in(position=2, keycard=True)
sign_in.wallet_button.click()
wallet.wait_balance_is_changed('ETH')
transaction_amount_keycard = wallet.get_unique_amount()
wallet.send_transaction(amount=transaction_amount_keycard, recipient=recipient, keycard=True,
sign_transaction=True)
for amount in [transaction_amount_keycard, transaction_amount_added]:
sign_in.just_fyi("Checking '%s' tx" % amount)
self.network_api.find_transaction_by_unique_amount(user['address'], amount)
self.errors.verify_no_errors()
@marks.testrail_id(695841)
@marks.medium
def test_keycard_settings_pin_puk_pairing(self):
sign_in = SignInView(self.driver)
seed = basic_user['passphrase']
home = sign_in.recover_access(passphrase=seed, keycard=True)
profile = home.profile_button.click()
home.just_fyi("Checking changing PIN")
profile.keycard_button.scroll_and_click()
keycard = profile.change_pin_button.click()
keycard.enter_another_pin()
keycard.wait_for_element_starts_with_text('2 attempts left', 30)
keycard.enter_default_pin()
if not keycard.element_by_translation_id("new-pin-description").is_element_displayed():
self.driver.fail("Screen for setting new pin is not shown!")
[keycard.enter_another_pin() for _ in range(2)]
if not keycard.element_by_translation_id("pin-changed").is_element_displayed(30):
self.driver.fail("Popup about successful setting new PIN is not shown!")
keycard.ok_button.click()
home.just_fyi("Checking changing PUK with new PIN")
profile.change_puk_button.click()
keycard.enter_another_pin()
if not keycard.element_by_translation_id("new-puk-description").is_element_displayed():
self.driver.fail("Screen for setting new puk is not shown!")
[keycard.one_button.click() for _ in range(12)]
if not keycard.element_by_translation_id("repeat-puk").is_element_displayed():
self.driver.fail("Confirmation screen for setting new puk is not shown!")
[keycard.one_button.click() for _ in range(12)]
if not keycard.element_by_translation_id("puk-changed").is_element_displayed(30):
self.driver.fail("Popup about successful setting new PUK is not shown!")
keycard.ok_button.click()
home.just_fyi("Checking setting pairing with new PIN")
profile.change_pairing_code_button.click()
keycard.enter_another_pin()
sign_in.create_password_input.set_value(common_password)
sign_in.confirm_your_password_input.set_value(common_password + "1")
if not keycard.element_by_translation_id("pairing-code_error1").is_element_displayed():
self.errors.append("No error is shown when pairing codes don't match")
sign_in.confirm_your_password_input.delete_last_symbols(1)
sign_in.element_by_translation_id("change-pairing").click()
if not keycard.element_by_translation_id("pairing-changed").is_element_displayed(30):
self.driver.fail("Popup about successful setting new pairing is not shown!")
keycard.ok_button.click()
home.just_fyi("Checking backing up keycard")
profile.create_keycard_backup_button.scroll_and_click()
sign_in.seedphrase_input.set_value(seed)
sign_in.next_button.click()
keycard.return_card_to_factory_settings_checkbox.enable()
keycard.begin_setup_button.click()
keycard.yes_button.wait_and_click()
[keycard.enter_another_pin() for _ in range(2)]
keycard.element_by_translation_id("keycard-backup-success-title").wait_for_element(30)
keycard.ok_button.click()
self.errors.verify_no_errors()
@marks.testrail_id(695851)
@marks.medium
def test_keycard_frozen_card_flows(self):
sign_in = SignInView(self.driver)
seed = basic_user['passphrase']
home = sign_in.recover_access(passphrase=seed, keycard=True)
profile = home.profile_button.click()
profile.keycard_button.scroll_and_click()
home.just_fyi('Set new PUK')
keycard = profile.change_puk_button.click()
keycard.enter_default_pin()
[keycard.enter_default_puk() for _ in range(2)]
keycard.ok_button.click()
home.just_fyi("Checking reset with PUK when logged in")
keycard = profile.change_pin_button.click()
keycard.enter_another_pin()
keycard.wait_for_element_starts_with_text('2 attempts left', 30)
keycard.enter_another_pin()
keycard.element_by_text_part('one attempt').wait_for_element(30)
keycard.enter_another_pin()
if not home.element_by_translation_id("keycard-is-frozen-title").is_element_displayed(30):
self.driver.fail("No popup about frozen keycard is shown!")
home.element_by_translation_id("keycard-is-frozen-reset").click()
keycard.enter_another_pin()
home.element_by_text_part('2/2').wait_for_element(20)
keycard.enter_another_pin()
home.element_by_translation_id("enter-puk-code").click()
keycard.enter_default_puk()
home.element_by_translation_id("keycard-access-reset").wait_for_element(20)
home.profile_button.double_click()
profile.logout()
home.just_fyi("Checking reset with PUK when logged out")
keycard.enter_default_pin()
keycard.wait_for_element_starts_with_text('2 attempts left', 30)
keycard.enter_default_pin()
keycard.element_by_text_part('one attempt').wait_for_element(30)
keycard.enter_default_pin()
if not home.element_by_translation_id("keycard-is-frozen-title").is_element_displayed():
self.driver.fail("No popup about frozen keycard is shown!")
home.element_by_translation_id("keycard-is-frozen-reset").click()
keycard.enter_another_pin()
home.element_by_text_part('2/2').wait_for_element(20)
keycard.enter_another_pin()
home.element_by_translation_id("enter-puk-code").click()
keycard.enter_default_puk()
home.element_by_translation_id("keycard-access-reset").wait_for_element(20)
home.element_by_translation_id("open").click()
home.just_fyi("Checking reset with seed when logged in")
profile = home.profile_button.click()
profile.keycard_button.scroll_and_click()
profile.change_pin_button.click()
keycard.enter_default_pin()
keycard.wait_for_element_starts_with_text('2 attempts left', 30)
keycard.enter_default_pin()
keycard.element_by_text_part('one attempt').wait_for_element(30)
keycard.enter_default_pin()
if not home.element_by_translation_id("keycard-is-frozen-title").is_element_displayed():
self.driver.fail("No popup about frozen keycard is shown!")
home.element_by_translation_id("dismiss").click()
profile.profile_button.double_click()
profile.keycard_button.scroll_and_click()
profile.change_pin_button.click()
keycard.enter_default_pin()
if not home.element_by_translation_id("keycard-is-frozen-title").is_element_displayed(30):
self.driver.fail("No reset card flow is shown for frozen card")
home.element_by_translation_id("keycard-is-frozen-factory-reset").click()
sign_in.seedphrase_input.set_value(transaction_senders['A']['passphrase'])
sign_in.next_button.click()
if not home.element_by_translation_id("seed-key-uid-mismatch").is_element_displayed():
self.driver.fail("No popup about mismatch in seed phrase is shown!")
home.element_by_translation_id("try-again").click()
sign_in.seedphrase_input.clear()
sign_in.seedphrase_input.set_value(seed)
sign_in.next_button.click()
keycard.begin_setup_button.click()
keycard.yes_button.click()
keycard.enter_default_pin()
home.element_by_translation_id("intro-wizard-title5").wait_for_element(20)
keycard.enter_default_pin()
home.element_by_translation_id("keycard-access-reset").wait_for_element(30)
home.ok_button.click()
profile.profile_button.double_click()
profile.logout()
home.just_fyi("Checking reset with seed when logged out")
keycard.enter_another_pin()
keycard.wait_for_element_starts_with_text('2 attempts left', 30)
keycard.enter_another_pin()
keycard.element_by_text_part('one attempt').wait_for_element(30)
keycard.enter_another_pin()
if not home.element_by_translation_id("keycard-is-frozen-title").is_element_displayed():
self.driver.fail("No popup about frozen keycard is shown!")
sign_in.element_by_translation_id("keycard-is-frozen-factory-reset").click()
sign_in.seedphrase_input.set_value(seed)
sign_in.next_button.click()
keycard.begin_setup_button.click()
keycard.yes_button.click()
keycard.enter_default_pin()
home.element_by_translation_id("intro-wizard-title5").wait_for_element(20)
keycard.enter_default_pin()
home.element_by_translation_id("keycard-access-reset").wait_for_element(30)
home.ok_button.click()
keycard.enter_default_pin()
home.home_button.wait_for_element(30)
@marks.testrail_id(695852)
@marks.medium
def test_keycard_blocked_card_lost_or_frozen_flows(self):
sign_in = SignInView(self.driver)
seed = basic_user['passphrase']
home = sign_in.recover_access(passphrase=seed, keycard=True)
profile = home.profile_button.click()
profile.keycard_button.scroll_and_click()
home.just_fyi("Checking blocked card screen when entering 3 times invalid PIN + 5 times invalid PUK")
keycard = profile.change_pin_button.click()
keycard.enter_another_pin()
keycard.wait_for_element_starts_with_text('2 attempts left', 30)
keycard.enter_another_pin()
keycard.element_by_text_part('one attempt').wait_for_element(30)
keycard.enter_another_pin()
if not home.element_by_translation_id("keycard-is-frozen-title").is_element_displayed():
self.driver.fail("No popup about frozen keycard is shown!")
home.element_by_translation_id("keycard-is-frozen-reset").click()
keycard.enter_another_pin()
home.element_by_text_part('2/2').wait_for_element(20)
keycard.enter_another_pin()
home.element_by_translation_id("enter-puk-code").click()
for i in range(1, 4):
keycard.enter_default_puk()
sign_in.wait_for_element_starts_with_text('%s attempts left' % str(5 - i))
i += 1
keycard.enter_default_puk()
sign_in.element_by_text_part('one attempt').wait_for_element(30)
keycard.enter_default_puk()
keycard.element_by_translation_id("keycard-is-blocked-title").wait_for_element(30)
keycard.close_button.click()
if not keycard.element_by_translation_id("keycard-blocked").is_element_displayed():
self.errors.append("In keycard settings there is no info that card is blocked")
keycard.back_button.click()
profile.logout()
home.just_fyi("Check blocked card when user is logged out and use lost or frozen to restore access")
keycard.enter_another_pin()
keycard.element_by_translation_id("keycard-is-blocked-title").wait_for_element(30)
keycard.element_by_translation_id("keycard-recover").click()
keycard.yes_button.click()
sign_in.seedphrase_input.set_value(seed)
sign_in.next_button.click()
keycard.begin_setup_button.click()
keycard.yes_button.click()
keycard.enter_default_pin()
home.element_by_translation_id("intro-wizard-title5").wait_for_element(20)
keycard.enter_default_pin()
home.element_by_translation_id("keycard-access-reset").wait_for_element(30)
home.ok_button.click()
keycard.enter_default_pin()
home.home_button.wait_for_element(30)
self.errors.verify_no_errors()
File diff suppressed because it is too large Load Diff
@@ -3,15 +3,14 @@ import string
import pytest
from tests import marks, common_password
from tests.base_test_case import MultipleSharedDeviceTestCase, create_shared_drivers
from tests.users import wallet_users, basic_user
from tests.base_test_case import SingleDeviceTestCase, MultipleSharedDeviceTestCase, create_shared_drivers
from tests.users import wallet_users, transaction_senders, basic_user, ens_user, ens_user_ropsten
from views.sign_in_view import SignInView
from support.utilities import get_merged_txs_list
@pytest.mark.xdist_group(name="wallet_management_1")
@marks.critical
@pytest.mark.run1
class TestWalletManagementDeviceMerged(MultipleSharedDeviceTestCase):
@classmethod
@@ -29,7 +28,7 @@ class TestWalletManagementDeviceMerged(MultipleSharedDeviceTestCase):
'STT': cls.wallet.get_asset_amount_by_name('STT')}
@marks.testrail_id(700756)
def test_wallet_tx_history_copy_tx_hash_on_cellular(self):
def test_wallet_tx_history_copy_tx_hash_on_lte(self):
self.wallet.accounts_status_account.click()
address = wallet_users['D']['address']
ropsten_txs = self.network_api.get_transactions(address)
@@ -95,7 +94,7 @@ class TestWalletManagementDeviceMerged(MultipleSharedDeviceTestCase):
self.wallet.just_fyi("Checking basic validation when adding multiaccount")
if self.wallet.get_account_by_name(account_name).is_element_displayed():
self.drivers[0].fail('Account is added without password')
self.wallet.enter_your_password_input.send_keys('000000')
self.wallet.enter_your_password_input.send_keys('00000000')
self.wallet.add_account_generate_account_button.click()
if not self.wallet.element_by_text_part('Password seems to be incorrect').is_element_displayed():
self.drivers[0].fail("Incorrect password validation is not performed")
@@ -390,4 +389,58 @@ class TestWalletManagementDeviceMerged(MultipleSharedDeviceTestCase):
self.errors.append(
"'Insufficient funds' error is not shown when sending %s STT from wallet with balance %s" % (
round(stt_value + 1), stt_value))
self.errors.verify_no_errors()
self.errors.verify_no_errors()
class TestWalletManagement(SingleDeviceTestCase):
@marks.testrail_id(6269)
@marks.medium
def test_search_asset_and_currency(self):
sign_in = SignInView(self.driver)
home = sign_in.create_user()
profile = home.profile_button.click()
profile.switch_network()
search_list_assets = {
'ad': ['AdEx', 'Open Trading Network', 'TrueCAD'],
'zs': ['ZSC']
}
wallet = home.wallet_button.click()
home.just_fyi('Searching for asset by name and symbol')
wallet.multiaccount_more_options.click()
wallet.manage_assets_button.click()
for keyword in search_list_assets:
home.search_by_keyword(keyword)
if keyword == 'ad':
search_elements = wallet.all_assets_full_names.find_elements()
else:
search_elements = wallet.all_assets_symbols.find_elements()
if not search_elements:
self.errors.append('No search results after searching by %s keyword' % keyword)
search_results = [element.text for element in search_elements]
if search_results != search_list_assets[keyword]:
self.errors.append("'%s' is shown on the home screen after searching by '%s' keyword" %
(', '.join(search_results), keyword))
home.cancel_button.click()
wallet.close_button.click()
home.just_fyi('Searching for currency')
search_list_currencies = {
'aF': ['Afghanistan Afghani (AFN)', 'South Africa Rand (ZAR)'],
'bolívi': ['Bolivia Bolíviano (BOB)']
}
wallet.multiaccount_more_options.click_until_presence_of_element(wallet.set_currency_button)
wallet.set_currency_button.click()
for keyword in search_list_currencies:
home.search_by_keyword(keyword)
search_elements = wallet.currency_item_text.find_elements()
if not search_elements:
self.errors.append('No search results after searching by %s keyword' % keyword)
search_results = [element.text for element in search_elements]
if search_results != search_list_currencies[keyword]:
self.errors.append("'%s' is shown on the home screen after searching by '%s' keyword" %
(', '.join(search_results), keyword))
home.cancel_button.click()
self.errors.verify_no_errors()
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,311 @@
import time
from tests import marks
from tests.users import transaction_senders, ens_user
from tests.base_test_case import MultipleDeviceTestCase
from views.sign_in_view import SignInView
class TestCommandsMultipleDevices(MultipleDeviceTestCase):
@marks.testrail_id(6253)
@marks.critical
@marks.transaction
def test_send_eth_in_1_1_chat_transaction_push(self):
sender = transaction_senders['ETH_7']
self.create_drivers(2)
device_1, device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
home_1 = device_1.recover_access(passphrase=sender['passphrase'], enable_notifications=True)
home_2 = device_2.create_user(enable_notifications=True)
for home in home_1, home_2:
profile = home.profile_button.click()
profile.profile_notifications_button.scroll_and_click()
profile.wallet_push_notifications.click()
recipient_public_key, recipient_username = home_2.get_public_key_and_username(return_username=True)
wallet_1, wallet_2 = home_1.wallet_button.click(), home_2.wallet_button.click()
[wallet.home_button.click() for wallet in (wallet_1, wallet_2)]
chat_1 = home_1.add_contact(recipient_public_key)
amount = chat_1.get_unique_amount()
account_name = wallet_1.status_account_name
home_1.just_fyi('Send %s ETH in 1-1 chat and check it for sender and receiver: Address requested' % amount)
chat_1.commands_button.click()
send_transaction = chat_1.send_command.click()
send_transaction.get_username_in_transaction_bottom_sheet_button(recipient_username).click()
if send_transaction.scan_qr_code_button.is_element_displayed():
self.drivers[0].fail('Recipient is editable in bottom sheet when send ETH from 1-1 chat')
send_transaction.amount_edit_box.set_value(amount)
send_transaction.confirm()
send_transaction.sign_transaction_button.click()
sender_message = chat_1.get_outgoing_transaction(account_name)
if not sender_message.is_element_displayed():
self.drivers[0].fail('No message is shown after sending ETH in 1-1 chat for sender')
sender_message.transaction_status.wait_for_element_text(sender_message.address_requested)
chat_2 = home_2.get_chat(sender['username']).click()
receiver_message = chat_2.get_incoming_transaction(account_name)
timestamp_sender = sender_message.timestamp_command_message.text
if not receiver_message.is_element_displayed():
self.drivers[0].fail('No message about incoming transaction in 1-1 chat is shown for receiver')
receiver_message.transaction_status.wait_for_element_text(receiver_message.address_requested)
home_2.just_fyi('Accept and share address for sender and receiver')
for option in (receiver_message.decline_transaction, receiver_message.accept_and_share_address):
if not option.is_element_displayed():
self.drivers[0].fail("Required options accept or share are not shown")
select_account_bottom_sheet = receiver_message.accept_and_share_address.click()
if not select_account_bottom_sheet.get_account_in_select_account_bottom_sheet_button(
account_name).is_element_displayed():
self.errors.append('Not expected value in "From" in "Select account": "Status" is expected')
select_account_bottom_sheet.select_button.click()
receiver_message.transaction_status.wait_for_element_text(receiver_message.shared_account)
sender_message.transaction_status.wait_for_element_text(sender_message.address_request_accepted)
home_1.just_fyi("Sign and send transaction and check that timestamp on message is updated")
time.sleep(20)
send_bottom_sheet = sender_message.sign_and_send.click()
send_bottom_sheet.next_button.click()
send_bottom_sheet.sign_transaction()
updated_timestamp_sender = sender_message.timestamp_command_message.text
if updated_timestamp_sender == timestamp_sender:
self.errors.append("Timestamp of message is not updated after signing transaction")
chat_1.wallet_button.click()
wallet_1.find_transaction_in_history(amount=amount)
[wallet.put_app_to_background() for wallet in (wallet_1, wallet_2)]
self.network_api.wait_for_confirmation_of_transaction(sender['address'], amount)
device_1.open_notification_bar()
device_1.element_by_text_part('You sent %s ETH' % amount).click()
if not wallet_1.transaction_history_button.is_element_displayed():
self.errors.append('Was not redirected to transaction history after tapping on PN')
wallet_1.home_button.click(desired_view="chat")
home_1.just_fyi("Check 'Confirmed' state for sender and receiver(use pull-to-refresh to update history)")
chat_2.status_in_background_button.click()
chat_2.wallet_button.click()
wallet_2.wait_balance_is_changed()
wallet_2.find_transaction_in_history(amount=amount)
wallet_2.home_button.click()
home_2.get_chat(sender['username']).click()
[message.transaction_status.wait_for_element_text(message.confirmed, 60) for message in
(sender_message, receiver_message)]
# TODO: should be added PNs for receiver after getting more stable feature (rechecked 23.11.21, valid)
self.errors.verify_no_errors()
@marks.testrail_id(6263)
@marks.critical
@marks.transaction
def test_request_and_receive_stt_in_1_1_chat_offline(self):
sender = transaction_senders['ETH_STT_3']
self.create_drivers(2)
device_1, device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
asset_name = 'STT'
amount = device_1.get_unique_amount()
device_1.just_fyi('Grab user data for transactions and public chat, set up wallets')
home_1 = device_1.create_user()
recipient_public_key, recipient_username = home_1.get_public_key_and_username(return_username=True)
wallet_1 = home_1.wallet_button.click()
wallet_1.select_asset(asset_name)
wallet_1.home_button.click()
home_2 = device_2.recover_access(passphrase=sender['passphrase'])
wallet_2 = home_2.wallet_button.click()
initial_amount_stt = wallet_2.get_asset_amount_by_name('STT')
wallet_2.home_button.click()
device_2.just_fyi('Add recipient to contact and send 1 message')
chat_2 = home_2.add_contact(recipient_public_key)
chat_2.send_message("Hey there!")
profile_2 = wallet_2.profile_button.click()
profile_2.logout()
chat_1 = home_1.get_chat(sender['username']).click()
home_1.just_fyi('Request %s STT in 1-1 chat and check it is visible for sender and receiver' % amount)
chat_1.commands_button.click()
request_transaction = chat_1.request_command.click()
request_transaction.amount_edit_box.set_value(amount)
request_transaction.confirm()
asset_button = request_transaction.asset_by_name(asset_name)
request_transaction.select_asset_button.click_until_presence_of_element(asset_button)
asset_button.click()
request_transaction.request_transaction_button.click()
chat_1_request_message = chat_1.get_incoming_transaction()
if not chat_1_request_message.is_element_displayed():
self.drivers[0].fail('No incoming transaction in 1-1 chat is shown for recipient after requesting STT')
home_2.just_fyi('Check that transaction message is fetched from offline and sign transaction')
device_2.sign_in()
home_2.connection_offline_icon.wait_for_invisibility_of_element(30)
home_2.get_chat(recipient_username).click()
chat_2_sender_message = chat_2.get_outgoing_transaction()
if not chat_2_sender_message.is_element_displayed():
self.drivers[0].fail('No outgoing transaction in 1-1 chat is shown for sender after requesting STT')
chat_2_sender_message.transaction_status.wait_for_element_text(chat_2_sender_message.address_received)
send_message = chat_2_sender_message.sign_and_send.click()
send_message.next_button.click()
send_message.sign_transaction()
home_2.just_fyi('Check that transaction message is updated with new status after offline')
[chat.toggle_airplane_mode() for chat in (chat_1, chat_2)]
self.network_api.wait_for_confirmation_of_transaction(sender['address'], amount, token=True)
for home in (home_1, home_2):
home.toggle_airplane_mode()
home.home_button.double_click()
home.connection_offline_icon.wait_for_invisibility_of_element(100)
home_1.get_chat(sender['username']).click()
home_2.get_chat(recipient_username).click()
[message.transaction_status.wait_for_element_text(message.confirmed, wait_time=120) for message in
(chat_2_sender_message, chat_1_request_message)]
home_1.just_fyi('Check that can find tx in history and balance is updated after offline')
home_2.wallet_button.click()
wallet_2.wait_balance_is_changed('STT', initial_amount_stt)
wallet_2.find_transaction_in_history(amount=amount, asset='STT')
self.errors.verify_no_errors()
@marks.testrail_id(6265)
@marks.critical
@marks.transaction
def test_decline_transactions_in_1_1_chat_push_notification_changing_state(self):
sender = transaction_senders['ETH_8']
self.create_drivers(2)
device_1, device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
home_1 = device_1.recover_access(passphrase=sender['passphrase'], enable_notifications=True)
home_2 = device_2.create_user()
profile_2 = home_2.profile_button.click()
recipient_chat_key = profile_2.get_public_key_and_username()
wallet_1, wallet_2 = home_1.wallet_button.click(), home_2.wallet_button.click()
[wallet.home_button.click() for wallet in (wallet_1, wallet_2)]
chat_1 = home_1.add_contact(recipient_chat_key)
amount = chat_1.get_unique_amount()
chat_1.send_message('To start conversation')
home_1.just_fyi('Decline transaction before sharing address and check that state is changed')
chat_1.commands_button.click()
send_transaction = chat_1.send_command.click()
send_transaction.amount_edit_box.set_value(amount)
send_transaction.confirm()
send_transaction.sign_transaction_button.click()
chat_1_sender_message = chat_1.get_outgoing_transaction()
home_1.click_system_home_button()
chat_2 = home_2.get_chat(sender['username']).click()
chat_2_receiver_message = chat_2.get_incoming_transaction()
chat_2_receiver_message.decline_transaction.click()
home_1.open_notification_bar()
home_1.element_by_text_part('Request address for transaction declined').wait_and_click()
[message.transaction_status.wait_for_element_text(message.declined) for message in
(chat_1_sender_message, chat_2_receiver_message)]
home_1.just_fyi('Decline transaction request and check that state is changed')
request_amount = chat_1.get_unique_amount()
chat_1.commands_button.click()
request_transaction = chat_1.request_command.click()
request_transaction.amount_edit_box.set_value(request_amount)
request_transaction.confirm()
request_transaction.request_transaction_button.click()
chat_1_request_message = chat_1.get_incoming_transaction()
chat_2_sender_message = chat_2.get_outgoing_transaction()
chat_2_sender_message.decline_transaction.click()
[message.transaction_status.wait_for_element_text(message.declined) for message in
(chat_2_sender_message, chat_1_request_message)]
self.errors.verify_no_errors()
@marks.testrail_id(6257)
@marks.medium
@marks.transaction
def test_network_mismatch_for_send_request_in_1_1_chat(self):
sender = transaction_senders['ETH_1']
self.create_drivers(2)
sign_in_1, sign_in_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
sign_in_1.recover_access(passphrase=sender['passphrase'])
sign_in_2.create_user()
home_1, home_2 = sign_in_1.get_home_view(), sign_in_2.get_home_view()
wallet_1 = home_1.wallet_button.click()
wallet_1.home_button.click()
profile_2 = home_2.profile_button.click()
username_2 = profile_2.default_username_text.text
profile_2.switch_network()
chat_2 = home_2.add_contact(sender['public_key'])
chat_2.send_message("Hey there!")
amount = chat_2.get_unique_amount()
chat_2.commands_button.click()
request_transaction = chat_2.request_command.click()
request_transaction.amount_edit_box.set_value(amount)
request_transaction.confirm()
request_transaction.request_transaction_button.click()
chat_2_request_message = chat_2.get_incoming_transaction()
chat_2_request_message.long_press_element()
if chat_2.reply_message_button.is_element_displayed():
self.errors.append('Reply is available on long-tap on Incoming transaction message!')
chat_1 = home_1.get_chat(username_2).click()
chat_1_sender_message = chat_1.get_outgoing_transaction()
chat_1_sender_message.long_press_element()
if chat_1.reply_message_button.is_element_displayed():
self.errors.append('Reply is available on long-tap on Outgoing transaction message!')
send_message = chat_1_sender_message.sign_and_send.click()
send_message.next_button.click()
send_message.sign_transaction()
self.network_api.wait_for_confirmation_of_transaction(sender['address'], amount)
chat_1_sender_message.transaction_status.wait_for_element_text(chat_1_sender_message.confirmed)
wallet_2 = chat_2.wallet_button.click()
wallet_2.accounts_status_account.click()
wallet_2.swipe_down()
wallet_2.home_button.click(desired_view="chat")
if chat_2_request_message.transaction_status == chat_1_sender_message.confirmed:
self.errors.append("Transaction is shown as confirmed on mainnet, but was sent on ropsten!")
self.errors.verify_no_errors()
@marks.testrail_id(6279)
@marks.high
@marks.transaction
def test_send_eth_to_ens_in_chat(self):
self.create_drivers(2)
sign_in_1, sign_in_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
sender, reciever = transaction_senders['ETH_3'], ens_user
home_1, home_2 = sign_in_1.recover_access(sender['passphrase']), sign_in_2.recover_access(
reciever['passphrase'])
home_2.just_fyi("Start chat with sender")
profile_2 = home_2.profile_button.click()
profile_2.connect_existing_ens(reciever['ens'])
profile_2.home_button.click()
chat_2 = home_2.add_contact(sender['public_key'])
message_1, message_2 = 'hello', 'hey'
chat_2.send_message(message_1)
wallet_1 = home_1.wallet_button.click()
wallet_1.wait_balance_is_changed()
wallet_1.home_button.click()
chat_1 = home_1.add_contact(reciever['ens'])
chat_1.send_message(message_2)
chat_1.commands_button.click()
amount = chat_1.get_unique_amount()
chat_1.just_fyi("Check sending assets to ENS name from sender side")
send_message = chat_1.send_command.click()
send_message.amount_edit_box.set_value(amount)
send_message.confirm()
send_message.next_button.click()
from views.send_transaction_view import SendTransactionView
send_transaction = SendTransactionView(self.drivers[0])
send_transaction.ok_got_it_button.click()
send_transaction.sign_transaction()
chat_1_sender_message = chat_1.get_outgoing_transaction(transaction_value=amount)
self.network_api.wait_for_confirmation_of_transaction(sender['address'], amount)
chat_1_sender_message.transaction_status.wait_for_element_text(chat_1_sender_message.confirmed)
chat_2.just_fyi("Check that message is fetched for receiver")
chat_2_reciever_message = chat_2.get_incoming_transaction(transaction_value=amount)
chat_2_reciever_message.transaction_status.wait_for_element_text(chat_2_reciever_message.confirmed)
@@ -0,0 +1,173 @@
from tests import marks
from tests.base_test_case import MultipleDeviceTestCase
from views.sign_in_view import SignInView
from views.chat_view import CommunityView
class TestCommunitiesMultipleDevices(MultipleDeviceTestCase):
@marks.testrail_id(695842)
@marks.medium
@marks.flaky
def test_creating_community_accept_membership(self):
self.create_drivers(2)
home_1, home_2 = SignInView(self.drivers[0]).create_user(), SignInView(self.drivers[1]).create_user()
community_name, pub_chat_name, channel_name = "some name", home_1.get_random_chat_name(), "first_channel"
community_description, community_pic = "something in community", 'sauce_logo.png'
message, message_member = "message", "from member"
userkey_2, username_2 = home_2.get_public_key_and_username(return_username=True)
home_2.home_button.click()
community_1 = home_1.create_community(community_name, community_description, set_image=True,
file_name=community_pic)
channel_1 = community_1.add_channel(channel_name)
channel_1.send_message(message)
home_1.home_button.double_click()
home_1.just_fyi("Sending community link to public chat")
community_1 = home_1.get_chat(community_name, community=True).click()
community_link_text = community_1.copy_community_link()
pub_1 = home_1.join_public_chat(pub_chat_name)
pub_1.chat_message_input.paste_text_from_clipboard()
pub_1.send_message_button.click()
pub_1.get_back_to_home_view()
home_2.just_fyi("Tapping on community link and request membership")
pub_2 = home_2.join_public_chat(pub_chat_name)
pub_2.element_by_text(community_name).wait_for_element(100)
community_message_2 = pub_2.get_community_link_preview_by_text(community_link_text)
if community_message_2.community_description != community_description:
self.errors.append(
"Community description '%s' does not match expected" % community_message_2.community_description)
if community_message_2.community_members_amount != 1:
self.errors.append("Members amount in resolved message '%s' does not match expected" % str(
community_message_2.community_members_amount))
community_message_2.view()
community_2 = CommunityView(self.drivers[1])
community_2.request_access_button.click()
if not community_2.membership_request_pending_text.is_element_displayed():
self.errors.append("Membership request is not pending")
home_1.just_fyi("Checking pending membership")
community_1 = home_1.get_chat(community_name, community=True).click()
community_1.community_options_button.click()
community_1.community_info_button.click()
community_1.community_membership_request_value.wait_for_element(60)
if community_1.community_membership_request_value.text != '1':
self.drivers[0].fail(
"Membership request value '%s' is not equal expected" % community_1.community_membership_request_value)
home_1.just_fyi("Approve membership")
community_1.handle_membership_request(username_2, approve=True)
if not community_1.element_by_text(username_2).is_element_displayed():
self.errors.append("New member %s is not shown as added to community on info page!" % username_2)
if not community_2.community_info_picture.is_element_image_similar_to_template(community_pic):
self.errors.append("Community image is different!")
channel_2 = community_2.get_chat(channel_name).click()
if not channel_2.chat_element_by_text(message).is_element_displayed(30):
self.errors.append("Message was not received in community channel!")
channel_2.send_message(message_member)
community_1.home_button.double_click()
home_1.get_chat(community_name, community=True).click()
chat_element_1 = community_1.get_chat(channel_name)
if not chat_element_1.new_messages_public_chat.is_element_displayed():
self.errors.append("Unread messages counter is not shown for community channel!")
if not community_1.element_by_text(message_member).is_element_displayed():
self.errors.append("Message from member is not shown for community channel!")
self.errors.verify_no_errors()
@marks.testrail_id(695845)
@marks.medium
def test_notification_in_activity_center_for_mention_in_community_and_group_chat(self):
self.create_drivers(2)
home_1, home_2 = SignInView(self.drivers[0]).create_user(), SignInView(self.drivers[1]).create_user()
community_name, gr_chat_name, channel_name = "some name", home_1.get_random_chat_name(), "first_channel"
community_description = "something in community"
message, message_member = "message", "from member"
userkey_2, username_2 = home_2.get_public_key_and_username(return_username=True)
userkey_1, username_1 = home_1.get_public_key_and_username(return_username=True)
home_1.home_button.click()
one_to_one_1 = home_1.add_contact(userkey_2)
one_to_one_1.home_button.click()
home_2.home_button.click()
home_1.just_fyi("Create community on Device_1")
community_1 = home_1.create_community(community_name, community_description, set_image=True)
channel_1 = community_1.add_channel(channel_name)
channel_1.send_message(message)
home_1.home_button.double_click()
home_1.just_fyi("Joining Group chat, receiving community link in there")
one_to_one_2 = home_2.add_contact(userkey_1)
one_to_one_2.home_button.click()
community_1 = home_1.get_chat(community_name, community=True).click()
community_link_text = community_1.copy_community_link()
pub_1 = home_1.create_group_chat(user_names_to_add=[username_2], group_chat_name=gr_chat_name)
pub_2 = home_2.get_chat(gr_chat_name).click()
pub_2.join_chat_button.click()
pub_1.chat_message_input.paste_text_from_clipboard()
pub_1.send_message_button.click()
pub_1.get_back_to_home_view()
home_2.just_fyi("Tapping on community link and request membership")
pub_2.element_by_text(community_name).wait_for_element(60)
community_message_2 = pub_2.get_community_link_preview_by_text(community_link_text)
community_2 = community_message_2.view()
community_2.request_access_button.click()
if not community_2.membership_request_pending_text.is_element_displayed():
self.errors.append("Membership request is not pending")
home_1.just_fyi("Checking pending membership")
community_1 = home_1.get_chat(community_name, community=True).click()
community_1.community_options_button.click()
community_1.community_info_button.click()
community_1.community_membership_request_value.wait_for_element(60)
home_1.just_fyi("Approve membership")
community_1.handle_membership_request(username_2, approve=True)
channel_2 = community_2.get_chat(channel_name).click()
channel_2.select_mention_from_suggestion_list(username_1, username_1[:2])
channel_2.send_as_keyevent("community")
channel_mesage = username_1 + " community"
channel_2.send_message_button.click()
community_1.home_button.double_click()
channel_2.home_button.click()
home_2.get_chat_from_home_view(gr_chat_name).click()
pub_2.select_mention_from_suggestion_list(username_1, username_1[:2])
pub_2.send_as_keyevent("group")
group_chat_message = username_1 + " group"
pub_2.send_message_button.click()
if not home_1.notifications_unread_badge.is_element_displayed():
self.errors.append("Unread badge is NOT shown after receiving mentions from Group and Community")
home_1.notifications_unread_badge.wait_and_click(30)
home_1.just_fyi("Check there are two notifications from two chats are present in Activity Center")
if home_1.get_chat_from_activity_center_view(username_2).chat_message_preview == group_chat_message:
home_1.just_fyi("Open group chat where user mentioned and return to Activity Center")
home_1.get_chat_from_activity_center_view(username_2).click()
home_1.home_button.click()
home_1.notifications_button.click()
else:
self.errors.append("No mention in Activity Center for Group Chat")
if home_1.get_chat_from_activity_center_view(username_2).chat_message_preview == channel_mesage:
home_1.just_fyi("Open community chat where user mentioned and return to Activity Center")
home_1.get_chat_from_activity_center_view(username_2).click()
home_1.home_button.click()
else:
self.errors.append("No mention in Activity Center for community chat")
home_1.just_fyi("Check there are no unread messages counters on chats after message read")
if (home_1.notifications_unread_badge.is_element_present() or
home_1.get_chat_from_home_view(gr_chat_name).new_messages_counter.text == "1" or
home_1.get_chat_from_home_view(community_name).new_messages_counter.text == "1"):
self.errors.append("Unread message indicator is kept after all messages read in chats")
home_1.just_fyi("Check there is an empty view on Activity Center")
home_1.notifications_button.click()
if not home_1.element_by_translation_id('empty-activity-center').is_element_present():
self.errors.append("It appears Activity Center still has some chats after user opened all of them")
self.errors.verify_no_errors()
@@ -0,0 +1,301 @@
from tests import marks
from tests.base_test_case import MultipleDeviceTestCase, SingleDeviceTestCase, MultipleSharedDeviceTestCase, create_shared_drivers
from tests.users import transaction_senders, ens_user, chat_users
from views.sign_in_view import SignInView
import random
import emoji
class TestGroupChatMultipleDevice(MultipleDeviceTestCase):
@marks.testrail_id(5694)
@marks.medium
def test_make_admin_member_of_group_chat(self):
self.create_drivers(2)
device_1, device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
home_1, home_2 = device_1.create_user(), device_2.create_user()
public_key_1, username_1 = device_1.get_public_key_and_username(True)
device_1.home_button.click()
chat_name = home_1.get_random_chat_name()
device_2.just_fyi('Create and join to group chat')
device_2_key, device_2_username = device_2.get_public_key_and_username(True)
device_2.home_button.click()
home_1.add_contact(device_2_key)
home_1.get_back_to_home_view()
chat_1 = home_1.create_group_chat([device_2_username], chat_name)
chat_2 = home_2.get_chat(chat_name).click()
chat_2.join_chat_button.click()
device_1.just_fyi('Check group info view and options of users')
chat_1.chat_options.click()
group_info_1 = chat_1.group_info.click()
if not group_info_1.user_admin(username_1).is_element_displayed():
self.errors.append("Admin user is not marked as admin")
group_info_1.get_user_from_group_info(username_1).click()
if chat_1.profile_block_contact.is_element_displayed():
self.errors.append("Admin is redirected to own profile on tapping own username from group info")
group_info_1.get_user_from_group_info(device_2_username).click()
if not chat_1.profile_block_contact.is_element_displayed():
self.errors.append("Admin is not redirected to user profile on tapping member username from group info")
chat_1.close_button.click()
device_1.just_fyi('Made admin another user and check system message')
options = group_info_1.get_username_options(device_2_username).click()
options.make_admin_button.click()
admin_system_message = chat_1.has_been_made_admin_system_message(username_1, device_2_username)
for chat in (chat_1, chat_2):
if not chat.chat_element_by_text(admin_system_message).is_element_displayed():
self.errors.append("Message with test '%s' was not received" % admin_system_message)
device_2.just_fyi('Check Admin in group info and that "add members" is available')
chat_2.chat_options.click()
group_info_1 = chat_2.group_info.click()
for username in (username_1, device_2_username):
if not group_info_1.user_admin(username).is_element_displayed():
self.errors.append("Admin user is not marked as admin")
if not group_info_1.add_members.is_element_displayed():
self.errors.append("Add member button is not available for new admin")
self.errors.verify_no_errors()
@marks.testrail_id(6280)
@marks.medium
def test_rename_group_chat(self):
self.create_drivers(2)
device_1, device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
home_1, home_2 = device_1.create_user(), device_2.create_user()
device_1_key, device_1_username = device_1.get_public_key_and_username(True)
device_1.home_button.click()
initial_chat_name = home_1.get_random_chat_name()
device_2.just_fyi('Create and join group chat')
public_key_2, username_2 = device_2.get_public_key_and_username(True)
device_2.home_button.click()
home_1.add_contact(public_key_2)
home_1.get_back_to_home_view()
device_1_chat = home_1.create_group_chat([username_2], initial_chat_name)
device_2_chat = home_2.get_chat(initial_chat_name).click()
device_2_chat.join_chat_button.click()
device_2.just_fyi('Rename chat and check system messages')
new_chat_name = device_1_chat.get_random_chat_name()
device_1_chat.rename_chat_via_group_info(new_chat_name)
for chat in (device_1_chat, device_2_chat):
if not chat.element_by_text(
chat.create_system_message(device_1_username, initial_chat_name)).is_element_displayed():
self.errors.append('Initial system message about creating chta was changed!')
if not chat.element_by_text(
chat.changed_group_name_system_message(device_1_username, new_chat_name)).is_element_displayed():
self.errors.append('Message about changing chat name is not shown')
device_2.just_fyi('Check that you can see renamed chat')
device_2_chat.back_button.click()
home_2.get_chat(new_chat_name).wait_for_visibility_of_element(60)
self.errors.verify_no_errors()
@marks.testrail_id(6327)
@marks.medium
def test_nicknames_ens_group_chats(self):
self.create_drivers(2)
home_1 = SignInView(self.drivers[0]).create_user()
home_2 = SignInView(self.drivers[1]).recover_access(ens_user['passphrase'])
profile_1, profile_2 = [home.profile_button.click() for home in (home_1, home_2)]
key_1, username_1 = profile_1.get_public_key_and_username(return_username=True)
ens, full_ens, username_2 = ens_user['ens'], '@%s' % ens_user['ens'], ens_user['username']
profile_2.connect_existing_ens(ens)
[profile.home_button.click() for profile in (profile_1, profile_2)]
home_1.just_fyi('Set nickname, using emojis, special chars and cyrrilic chars without adding to contact')
emoji_message = random.choice(list(emoji.EMOJI_UNICODE))
emoji_unicode = emoji.EMOJI_UNICODE[emoji_message]
special_char, cyrrilic = '"£¢€¥~`•|√π¶∆×°™®©%$@', 'стат'
nickname_to_set = emoji.emojize(emoji_message) + special_char + cyrrilic
nickname_expected = emoji_unicode + special_char + cyrrilic
chat_1 = home_1.add_contact(ens, add_in_contacts=False, nickname=nickname_to_set)
if chat_1.user_name_text.text != nickname_expected:
self.errors.append('Expected special char nickname %s does not match actual %s' % (nickname_expected, chat_1.user_name_text.text))
home_1.just_fyi('Can remove nickname without adding to contact')
chat_1.chat_options.click()
chat_1.view_profile_button.click()
chat_1.profile_nickname_button.click()
chat_1.nickname_input_field.clear()
chat_1.element_by_text('Done').click()
chat_1.close_button.click()
if chat_1.user_name_text.text != full_ens:
self.errors.append(
'Nickname was not removed! real chat name is %s instead of %s' % (chat_1.user_name_text.text, full_ens))
home_1.just_fyi('Adding ENS user to contacts and start group chat with him')
group_name = 'ens_group'
chat_1.add_to_contacts.click()
chat_2 = home_2.add_contact(key_1)
chat_2.send_message("first")
chat_2.home_button.click()
chat_1.home_button.click()
chat_1 = home_1.create_group_chat([full_ens], group_name)
chat_2 = home_2.get_chat(group_name).click()
chat_2.join_chat_button.click()
home_1.just_fyi('Check ENS and in group chat and suggestions list')
chat_1.element_by_text_part(full_ens).wait_for_visibility_of_element(60)
chat_1.select_mention_from_suggestion_list(ens, typed_search_pattern=ens[:2])
if chat_1.chat_message_input.text != '@' + ens + ' ':
self.errors.append(
'ENS username is not resolved in chat input after selecting it in mention suggestions list!')
additional_text = 'and more'
chat_1.send_as_keyevent(additional_text)
chat_1.send_message_button.click()
message_text = '%s %s' % (full_ens, additional_text)
if not chat_1.chat_element_by_text(message_text).is_element_displayed():
self.errors.append("ENS name is not resolved on sent message")
chat_1 = home_1.get_chat_view()
home_1.just_fyi('Set nickname via group info and check that can mention by nickname /username in group chat')
nickname = 'funny_bunny'
device_2_options = chat_1.get_user_options(full_ens)
device_2_options.view_profile_button.click()
chat_1.set_nickname(nickname, close_profile=False)
if not chat_1.element_by_text(nickname).is_element_displayed():
self.errors.append('Nickname is not shown in profile view after setting from group info')
chat_1.close_button.click()
chat_1.element_by_text(nickname).scroll_to_element()
chat_1.close_button.click()
message_text = '%s %s' % (nickname, additional_text)
if not chat_1.chat_element_by_text(message_text).is_element_displayed():
self.errors.append("ENS name was not replaced with nickname on sent message")
chat_1.chat_message_input.send_keys('@')
if not chat_1.element_by_text('%s %s' % (nickname, full_ens)).is_element_displayed():
self.errors.append("ENS name with nickname is not shown in mention input after set")
if not chat_1.element_by_text(username_2).is_element_displayed():
self.errors.append("3-random name is not shown in mention input after set from group info")
chat_1.chat_message_input.clear()
chat_1.select_mention_from_suggestion_list('%s %s' % (nickname, full_ens), typed_search_pattern=username_2[:2])
if chat_1.chat_message_input.text != '@' + ens + ' ':
self.errors.append(
'ENS is not resolved in chat input after setting nickname in mention suggestions list (search by 3-random name)!')
chat_1.chat_message_input.clear()
chat_1.select_mention_from_suggestion_list('%s %s' % (nickname, full_ens), typed_search_pattern=nickname[:2])
if chat_1.chat_message_input.text != '@' + ens + ' ':
self.errors.append(
'ENS is not resolved in chat input after setting nickname in mention suggestions list (search by nickname)!')
chat_1.chat_message_input.clear()
home_1.just_fyi('Can delete nickname via group info and recheck received messages')
device_2_options = chat_1.get_user_options(full_ens)
device_2_options.view_profile_button.click()
chat_1.profile_nickname_button.click()
chat_1.nickname_input_field.clear()
chat_1.element_by_text('Done').click()
chat_1.close_button.click()
chat_1.close_button.click()
message_text = '%s %s' % (full_ens, additional_text)
if not chat_1.chat_element_by_text(message_text).is_element_displayed():
self.errors.append("ENS name is not resolved on sent message after removing nickname")
chat_1.chat_message_input.send_keys('@')
if chat_1.element_by_text_part(nickname).is_element_displayed():
self.errors.append("Nickname is shown in group chat after removing!")
self.errors.verify_no_errors()
@marks.testrail_id(5752)
@marks.medium
def test_block_and_unblock_user_from_group_chat_via_group_info(self):
self.create_drivers(2)
device_1, device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
home_1, home_2 = device_1.create_user(), device_2.create_user()
initial_chat_name = home_1.get_random_chat_name()
device_2.just_fyi('Create and join group chat')
public_key_2, username_2 = device_2.get_public_key_and_username(True)
device_2.home_button.click()
home_1.add_contact(public_key_2)
home_1.get_back_to_home_view()
chat_1 = home_1.create_group_chat([username_2], initial_chat_name)
chat_2 = home_2.get_chat(initial_chat_name).click()
chat_2.join_chat_button.click()
device_2.just_fyi('Send message and block user via Group Info')
message_before_block = 'message from device2'
chat_2.send_message(message_before_block)
options_2 = chat_1.get_user_options(username_2)
options_2.view_profile_button.click()
options_2.block_contact()
home_1.close_button.click()
if chat_1.chat_element_by_text(message_before_block).is_element_displayed(10):
self.errors.append('User was blocked, but past message are shown')
message_after_block = 'message from device2 after block'
chat_2.send_message(message_after_block)
if chat_1.chat_element_by_text(message_after_block).is_element_displayed(10):
self.errors.append('User was blocked, but new messages still received')
device_1.just_fyi('Unblock user via group info and check that new messages will arrive')
options_2 = chat_1.get_user_options(username_2)
options_2.view_profile_button.click()
options_2.unblock_contact_button.click()
[options_2.close_button.click() for _ in range(2)]
message_after_unblock = 'message from device2 after unblock'
chat_2.send_message(message_after_unblock)
if not chat_1.chat_element_by_text(message_after_unblock).is_element_displayed(20):
self.errors.append('User was unblocked, but new messages are not received')
self.errors.verify_no_errors()
class TestCommandsSingleDevices(SingleDeviceTestCase):
@marks.testrail_id(5721)
@marks.medium
def test_cant_add_more_twenty_participants_to_group_chat(self):
sign_in = SignInView(self.driver)
home = sign_in.create_user()
users = [chat_users['A'],
chat_users['B'],
transaction_senders['ETH_8'],
transaction_senders['ETH_1'],
transaction_senders['ETH_2'],
transaction_senders['ETH_7'],
transaction_senders['ETH_STT_3'],
transaction_senders['ETH_STT_ADI_1'],
transaction_senders['C'],
transaction_senders['F'],
transaction_senders['G'],
transaction_senders['H'],
transaction_senders['I'],
transaction_senders['M'],
transaction_senders['N'],
transaction_senders['Q'],
transaction_senders['R'],
transaction_senders['S'],
transaction_senders['T'],
transaction_senders['U']]
usernames = []
home.just_fyi('Add 20 users to contacts')
profile = home.profile_button.click()
profile.contacts_button.click()
chat = home.get_chat_view()
for user in users:
profile.add_new_contact_button.click()
chat.public_key_edit_box.click()
chat.public_key_edit_box.set_value(user['public_key'])
chat.confirm_until_presence_of_element(profile.add_new_contact_button)
usernames.append(user['username'])
home.just_fyi('Create group chat with max amount of users')
profile.home_button.click()
chat = home.create_group_chat(usernames, 'some_group_chat')
home.just_fyi('Verify that can not add more users via group info')
chat.get_back_to_home_view()
home.get_chat('some_group_chat').click()
chat.chat_options.click()
group_info_view = chat.group_info.click()
if group_info_view.add_members.is_element_displayed():
self.errors.append('Add members button is displayed when max users are added in chat')
if not group_info_view.element_by_text_part('20 members').is_element_displayed():
self.errors.append('Amount of users is not shown on Group info screen')
self.errors.verify_no_errors()
@@ -0,0 +1,188 @@
import time
from tests import marks
from tests.users import transaction_senders, ens_user_ropsten
from tests.base_test_case import MultipleDeviceTestCase, SingleDeviceTestCase
from views.sign_in_view import SignInView
class TestCommandsMultipleDevices(MultipleDeviceTestCase):
@marks.testrail_id(6293)
@marks.critical
@marks.transaction
def test_keycard_send_eth_in_1_1_chat(self):
sender = transaction_senders['ETH_2']
self.create_drivers(2)
device_1, device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
home_1 = device_1.recover_access(passphrase=sender['passphrase'], keycard=True)
home_2 = device_2.create_user(keycard=True)
recipient_public_key, recipient_username = home_2.get_public_key_and_username(return_username=True)
home_2.home_button.click()
chat_1 = home_1.add_contact(recipient_public_key)
amount = chat_1.get_unique_amount()
account_name = chat_1.status_account_name
home_1.just_fyi('Send %s ETH in 1-1 chat and check it for sender and receiver: Address requested' % amount)
chat_1.commands_button.click()
send_transaction = chat_1.send_command.click()
send_transaction.get_username_in_transaction_bottom_sheet_button(recipient_username).click()
if send_transaction.scan_qr_code_button.is_element_displayed():
self.drivers[0].fail('Recipient is editable in bottom sheet when send ETH from 1-1 chat')
send_transaction.amount_edit_box.set_value(amount)
send_transaction.confirm()
send_transaction.sign_transaction_button.click()
sender_message = chat_1.get_outgoing_transaction()
if not sender_message.is_element_displayed():
self.drivers[0].fail('No message is shown after sending ETH in 1-1 chat for sender')
sender_message.transaction_status.wait_for_element_text(sender_message.address_requested)
chat_2 = home_2.get_chat(sender['username']).click()
receiver_message = chat_2.get_incoming_transaction()
timestamp_sender = sender_message.timestamp_command_message.text
if not receiver_message.is_element_displayed():
self.drivers[0].fail('No message about incoming transaction in 1-1 chat is shown for receiver')
receiver_message.transaction_status.wait_for_element_text(receiver_message.address_requested)
home_2.just_fyi('Accept and share address for sender and receiver')
for option in (receiver_message.decline_transaction, receiver_message.accept_and_share_address):
if not option.is_element_displayed():
self.drivers[0].fail("Required options accept or share are not shown")
select_account_bottom_sheet = receiver_message.accept_and_share_address.click()
if not select_account_bottom_sheet.get_account_in_select_account_bottom_sheet_button(
account_name).is_element_displayed():
self.errors.append('Not expected value in "From" in "Select account": "Status" is expected')
select_account_bottom_sheet.select_button.click()
receiver_message.transaction_status.wait_for_element_text(receiver_message.shared_account)
sender_message.transaction_status.wait_for_element_text(sender_message.address_request_accepted)
home_1.just_fyi("Sign and send transaction and check that timestamp on message is updated")
time.sleep(20)
send_message = sender_message.sign_and_send.click()
send_message.next_button.click()
send_message.sign_transaction(keycard=True)
updated_timestamp_sender = sender_message.timestamp_command_message.text
if updated_timestamp_sender == timestamp_sender:
self.errors.append("Timestamp of message is not updated after signing transaction")
wallet_1 = chat_1.wallet_button.click()
wallet_1.find_transaction_in_history(amount=amount)
self.network_api.wait_for_confirmation_of_transaction(sender['address'], amount)
wallet_1.home_button.click(desired_view='chat')
home_1.just_fyi("Check 'Confirmed' state for sender and receiver(use pull-to-refresh to update history)")
wallet_2 = chat_2.wallet_button.click()
wallet_2.find_transaction_in_history(amount=amount)
sender_message.transaction_status.wait_for_element_text(sender_message.confirmed, 120)
self.errors.verify_no_errors()
@marks.testrail_id(6294)
@marks.medium
@marks.transaction
def test_keycard_request_and_receive_stt_in_1_1_chat_offline_opened_from_push(self):
sender = transaction_senders['ETH_STT_1']
self.create_drivers(2)
device_1, device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
device_1.just_fyi('Grab user data for transactions and public chat, set up wallets')
home_1 = device_1.create_user(keycard=True)
recipient_public_key, recipient_username = home_1.get_public_key_and_username(return_username=True)
amount = device_1.get_unique_amount()
asset_name = 'STT'
wallet_1 = home_1.wallet_button.click()
wallet_1.select_asset(asset_name)
wallet_1.home_button.click()
home_2 = device_2.recover_access(passphrase=sender['passphrase'], keycard=True, enable_notifications=True)
wallet_2 = home_2.wallet_button.click()
initial_amount_stt = wallet_2.get_asset_amount_by_name('STT')
wallet_2.home_button.click()
device_2.just_fyi('Add recipient to contact and send 1 message')
chat_2 = home_2.add_contact(recipient_public_key)
chat_2.send_message("Hey there!")
profile_2 = wallet_2.profile_button.click()
profile_2.airplane_mode_button.click()
device_2.home_button.double_click()
chat_element = home_1.get_chat(sender['username'])
chat_element.wait_for_visibility_of_element(30)
chat_1 = chat_element.click()
home_1.just_fyi('Request %s STT in 1-1 chat and check it is visible for sender and receiver' % amount)
chat_1.commands_button.click()
request_transaction = chat_1.request_command.click()
request_transaction.amount_edit_box.set_value(amount)
request_transaction.confirm()
asset_button = request_transaction.asset_by_name(asset_name)
request_transaction.select_asset_button.click_until_presence_of_element(asset_button)
asset_button.click()
request_transaction.request_transaction_button.click()
chat_1_request_message = chat_1.get_incoming_transaction()
if not chat_1_request_message.is_element_displayed():
self.drivers[0].fail('No incoming transaction in 1-1 chat is shown for recipient after requesting STT')
home_2.just_fyi('Check that transaction message is fetched from offline and sign transaction')
profile_2.airplane_mode_button.click()
transaction_request_pn = 'Request transaction'
device_2.open_notification_bar()
if not device_2.element_by_text(transaction_request_pn).is_element_displayed(60):
self.errors.append("Push notification is not received after going back from offline")
device_2.element_by_text(transaction_request_pn).click()
home_2.connection_offline_icon.wait_for_invisibility_of_element(120)
home_2.get_chat(recipient_username).click()
chat_2_sender_message = chat_2.get_outgoing_transaction()
chat_2_sender_message.wait_for_visibility_of_element(60)
chat_2_sender_message.transaction_status.wait_for_element_text(chat_2_sender_message.address_received)
send_message = chat_2_sender_message.sign_and_send.click()
send_message.next_button.click()
send_message.sign_transaction(keycard=True)
chat_1.toggle_airplane_mode()
home_2.just_fyi('Check that transaction message is updated with new status after offline')
[chat.toggle_airplane_mode() for chat in (chat_1, chat_2)]
self.network_api.wait_for_confirmation_of_transaction(sender['address'], amount, token=True)
for home in (home_1, home_2):
home.toggle_airplane_mode()
home.home_button.double_click()
home_1.get_chat(sender['username']).click()
home_2.get_chat(recipient_username).click()
chat_2_sender_message.transaction_status.wait_for_element_text(chat_2_sender_message.confirmed, wait_time=120)
home_1.just_fyi('Check that can find tx in history and balance is updated after offline')
[home.wallet_button.click() for home in (home_1, home_2)]
wallet_2.wait_balance_is_changed('STT', initial_amount_stt)
wallet_1.wait_balance_is_changed('STT', scan_tokens=True)
[wallet.find_transaction_in_history(amount=amount, asset='STT') for wallet in (wallet_1, wallet_2)]
self.errors.verify_no_errors()
class TestCommandsSingleDevices(SingleDeviceTestCase):
@marks.testrail_id(6295)
@marks.medium
@marks.transaction
def test_keycard_send_eth_to_ens(self):
sign_in = SignInView(self.driver)
sender = transaction_senders['ETH_4']
home = sign_in.recover_access(sender['passphrase'], keycard=True)
wallet = home.wallet_button.click()
wallet.home_button.click()
chat = home.add_contact(ens_user_ropsten['ens'])
chat.commands_button.click()
amount = chat.get_unique_amount()
send_message = chat.send_command.click()
send_message.amount_edit_box.set_value(amount)
send_message.confirm()
send_message.next_button.click()
from views.send_transaction_view import SendTransactionView
send_transaction = SendTransactionView(self.driver)
send_transaction.sign_transaction(keycard=True)
chat_sender_message = chat.get_outgoing_transaction()
self.network_api.wait_for_confirmation_of_transaction(sender['address'], amount)
chat_sender_message.transaction_status.wait_for_element_text(chat_sender_message.confirmed)
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,173 @@
from tests import marks
from tests.base_test_case import SingleDeviceTestCase
from views.sign_in_view import SignInView
class TestBrowsing(SingleDeviceTestCase):
@marks.testrail_id(5395)
@marks.medium
def test_back_forward_refresh_navigation_history_kept_after_relogin(self):
sign_in = SignInView(self.driver)
home = sign_in.create_user()
dapp = home.dapp_tab_button.click()
ru_url = 'https://ru.m.wikipedia.org'
browsing = dapp.open_url(ru_url)
browsing.element_by_text_part('Добро пожаловать').wait_for_element(20)
browsing.just_fyi("Check next page")
browsing.just_fyi('Navigate to next page and back')
browsing.element_by_text_part('свободную энциклопедию').click()
browsing.element_by_text_part('Свободный контент')
browsing.browser_previous_page_button.click()
browsing.wait_for_element_starts_with_text('свободную энциклопедию')
browsing.just_fyi('Relogin and check that tap on "Next" navigates to next page')
profile = home.profile_button.click()
profile.switch_network()
home.dapp_tab_button.click()
browsing.open_tabs_button.click()
dapp.element_by_text_part(ru_url).click()
browsing.wait_for_element_starts_with_text('свободную энциклопедию')
browsing.browser_next_page_button.click()
browsing.element_by_text_part('Свободный контент').wait_for_element(30)
browsing.just_fyi("Check refresh button")
browsing.open_tabs_button.click()
browsing.empty_tab_button.click()
url = 'app.uniswap.org'
element_on_start_page = dapp.element_by_text('Select a token')
web_page = dapp.open_url(url)
dapp.allow_button.click()
element_on_start_page.scroll_and_click()
# when bottom sheet is opened, elements by text couldn't be found
element_on_start_page.wait_for_invisibility_of_element(20)
web_page.browser_refresh_page_button.click()
if not element_on_start_page.is_element_displayed(30):
self.driver.fail("Page failed to be refreshed")
@marks.testrail_id(5424)
@marks.medium
def test_open_url_with_non_english_text_connect_revoke_wallet_new_tab_open_chat_options(self):
home = SignInView(self.driver).create_user()
web_view = home.dapp_tab_button.click()
browsing = web_view.open_url('www.wikipedia.org')
wiki_texts = ['Español', '日本語', 'Français', '中文', 'Português']
for wiki_text in wiki_texts:
if not browsing.element_by_text_part(wiki_text).is_element_displayed(15):
self.errors.append("%s is not shown" % wiki_text)
web_view.just_fyi("Check that can connect wallet and revoke access")
browsing.options_button.click()
browsing.connect_account_button.click()
browsing.allow_button.click()
browsing.options_button.click()
if not browsing.connected_account_button.is_element_displayed():
self.driver.fail("Account is not connected")
browsing.click_system_back_button()
profile = browsing.profile_button.click()
profile.privacy_and_security_button.click()
profile.dapp_permissions_button.click()
if not profile.element_by_text('wikipedia.org').is_element_displayed():
self.errors.append("Permissions are not granted")
profile.dapp_tab_button.click(desired_element_text=wiki_texts[0])
browsing.options_button.click()
browsing.connected_account_button.click()
browsing.element_by_translation_id("revoke-access").click()
browsing.options_button.click()
if not browsing.connect_account_button.is_element_displayed():
self.errors.append("Permission for account is not removed if using 'Revoke access' from dapp view")
browsing.click_system_back_button()
browsing.profile_button.click(desired_element_text='DApp permissions')
if profile.element_by_text('wikipedia.org').is_element_displayed():
self.errors.append("Permissions are not revoked")
web_view.just_fyi("Check that can open chat view and send some message")
profile.dapp_tab_button.click(desired_element_text=wiki_texts[0])
browsing.options_button.click()
browsing.open_chat_from_dapp_button.click()
public_chat = browsing.get_chat_view()
if not public_chat.element_by_text('#wikipedia-org').is_element_displayed():
self.driver.fail("No redirect to public chat")
message = public_chat.get_random_message()
public_chat.send_message(message)
public_chat.dapp_tab_button.click(desired_element_text=wiki_texts[0])
browsing.options_button.click()
browsing.open_chat_from_dapp_button.click()
if not public_chat.chat_element_by_text(message).is_element_displayed():
self.errors.append("Messages are not shown if open dapp chat from view")
web_view.just_fyi("Check that can open new tab using 'New tab' from bottom sheet")
profile.dapp_tab_button.click(desired_element_text=wiki_texts[0])
browsing.options_button.click()
browsing.new_tab_button.click()
if not browsing.element_by_translation_id("open-dapp-store").is_element_displayed():
self.errors.append("Was not redirected to home dapp store view using New tab")
self.errors.verify_no_errors()
# TODO: waiting mode (rechecked 23.11.21, valid)
@marks.testrail_id(6300)
@marks.skip
@marks.medium
def test_webview_security(self):
home_view = SignInView(self.driver).create_user()
daap_view = home_view.dapp_tab_button.click()
browsing_view = daap_view.open_url('https://simpledapp.status.im/webviewtest/url-spoof-ssl.html')
browsing_view.url_edit_box_lock_icon.click()
if not browsing_view.element_by_translation_id("browser-not-secure").is_element_displayed():
self.errors.append("Broken certificate displayed as secure connection \n")
browsing_view.cross_icon.click()
daap_view.open_url('https://simpledapp.status.im/webviewtest/webviewtest.html')
browsing_view.element_by_text_part('204').click()
if browsing_view.element_by_text_part('google.com').is_element_displayed():
self.errors.append("URL changed on attempt to redirect to no-content page \n")
browsing_view.cross_icon.click()
daap_view.open_url('https://simpledapp.status.im/webviewtest/webviewtest.html')
browsing_view.element_by_text_part('XSS check').click()
browsing_view.open_in_status_button.click()
if browsing_view.element_by_text_part('simpledapp.status.im').is_element_displayed():
self.errors.append("XSS attemp succedded \n")
browsing_view.ok_button.click()
browsing_view.cross_icon.click()
daap_view.open_url('https://simpledapp.status.im/webviewtest/url-blank.html')
if daap_view.edit_url_editbox.text == '':
self.errors.append("Blank URL value. Must show the actual URL \n")
browsing_view.cross_icon.click()
daap_view.open_url('https://simpledapp.status.im/webviewtest/port-timeout.html')
# wait up ~2.5 mins for port time out
if daap_view.element_by_text_part('example.com').is_element_displayed(150):
self.errors.append("URL spoof due to port timeout \n")
self.errors.verify_no_errors()
@marks.testrail_id(5456)
@marks.medium
def test_can_access_images_by_link(self):
urls = {
'https://cdn.dribbble.com/users/45534/screenshots/3142450/logo_dribbble.png':
'url1.png',
'https://steemitimages.com/DQmYEjeBuAKVRa3b3ZqwLicSHaPUm7WFtQqohGaZdA9ghjx/images%20(4).jpeg':
'url3.png'
}
sign_in_view = SignInView(self.driver)
home_view = sign_in_view.create_user()
dapp_view = home_view.dapp_tab_button.click()
from views.web_views.base_web_view import BaseWebView
base_web = BaseWebView(self.driver)
for url in urls:
self.driver.set_clipboard_text(url)
dapp_view.enter_url_editbox.click()
dapp_view.paste_text()
dapp_view.confirm()
base_web.wait_for_d_aap_to_load(20)
if dapp_view.web_page.is_element_differs_from_template(urls[url], 5):
self.errors.append('Web page does not match expected template %s' % urls[url])
base_web.browser_previous_page_button.click_until_presence_of_element(dapp_view.enter_url_editbox)
self.errors.verify_no_errors()
@@ -0,0 +1,143 @@
from tests import marks, test_dapp_name
from tests.base_test_case import SingleDeviceTestCase
from tests.users import basic_user
from views.sign_in_view import SignInView
class TestDApps(SingleDeviceTestCase):
@marks.testrail_id(6635)
@marks.medium
def test_webview_camera_permission(self):
web_view_camera_url = 'https://simpledapp.status.im/webviewtest/webviewcamera.html'
home = SignInView(self.driver).create_user()
self.driver.set_clipboard_text(web_view_camera_url)
dapp = home.dapp_tab_button.click()
dapp.enter_url_editbox.click()
dapp.paste_text()
dapp.confirm()
from views.web_views.base_web_view import BaseWebView
camera_dapp = BaseWebView(self.driver)
camera_dapp.just_fyi("Check camera request blocked (because it's not enabled in app yet)")
camera_request_blocked = home.get_translation_by_key("page-camera-request-blocked")
if not dapp.element_by_text_part(camera_request_blocked).is_element_displayed():
self.driver.fail("There is no pop-up notifying that camera access need to be granted in app")
camera_dapp.swipe_down()
if not camera_dapp.camera_image_in_dapp.is_element_image_similar_to_template('blank_camera_image.png'):
self.driver.fail("Even camera permissions not allowed - acccess to camera granted")
profile = home.profile_button.click()
profile.privacy_and_security_button.click()
camera_dapp.just_fyi("Enable camera requests in Dapps")
profile.element_by_translation_id("webview-camera-permission-requests").scroll_and_click()
home.dapp_tab_button.click(desired_element_text='webview')
camera_dapp.just_fyi("Check DApp asks now to allow camera aceess but Deny in DApp")
camera_dapp.browser_refresh_page_button.click()
camera_dapp.deny_button.click()
if not camera_dapp.camera_image_in_dapp.is_element_image_similar_to_template('blank_camera_image.png'):
self.driver.fail("Even camera access Denied to Dapp, - acccess to camera granted")
camera_dapp.just_fyi("Check DApp asks now to allow camera aceess and Allow access to DApp")
camera_dapp.browser_refresh_page_button.click()
camera_dapp.allow_button.click()
if camera_dapp.camera_image_in_dapp.is_element_image_similar_to_template('blank_camera_image.png'):
self.driver.fail("Even camera access Accepted to Dapp, - camera view is not shown")
camera_dapp.just_fyi("Relogin and check camera access still needs to be allowed")
home.profile_button.click()
profile.relogin()
home.dapp_tab_button.click()
camera_dapp.open_tabs_button.click()
dapp.element_by_text_part("https").click()
if not camera_dapp.allow_button.is_element_displayed():
self.driver.fail("No request to camera access after relogin")
@marks.testrail_id(6323)
@marks.medium
@marks.flaky
def test_resolve_ipns_name(self):
user = basic_user
ipns_url = 'uniswap.eth'
home = SignInView(self.driver).recover_access(passphrase=user['passphrase'])
profile = home.profile_button.click()
profile.switch_network()
self.driver.set_clipboard_text(ipns_url)
dapp = home.dapp_tab_button.click()
dapp.enter_url_editbox.click()
dapp.paste_text()
dapp.confirm()
if not dapp.allow_button.is_element_displayed(30):
self.driver.fail('No permission is asked for dapp, so IPNS name is not resolved')
@marks.testrail_id(6232)
@marks.medium
@marks.flaky
# TODO: due to 13011
def test_switching_accounts_in_dapp(self):
home = SignInView(self.driver).create_user()
wallet = home.wallet_button.click()
wallet.just_fyi('create new account in multiaccount')
status_account = home.status_account_name
account_name = 'Subaccount'
wallet.add_account(account_name)
address = wallet.get_wallet_address(account_name)
home.just_fyi('can see two accounts in DApps')
dapp = home.dapp_tab_button.click()
dapp.select_account_button.click()
for text in 'Select the account', status_account, account_name:
if not dapp.element_by_text_part(text).is_element_displayed():
self.driver.fail("No expected element %s is shown in menu" % text)
home.just_fyi('add permission to Status account')
dapp.enter_url_editbox.click()
status_test_dapp = home.open_status_test_dapp()
home.just_fyi('check that permissions from previous account was removed once you choose another')
dapp.select_account_button.click()
dapp.select_account_by_name(account_name).wait_for_element(30)
dapp.select_account_by_name(account_name).click()
profile = dapp.profile_button.click()
profile.privacy_and_security_button.click()
profile.dapp_permissions_button.click()
if profile.element_by_text(test_dapp_name).is_element_displayed():
self.errors.append("Permissions for %s are not removed" % test_dapp_name)
home.just_fyi('check that can change account')
profile.dapp_tab_button.click()
if not status_test_dapp.element_by_text_part(account_name).is_element_displayed():
self.errors.append("No expected account %s is shown in authorize web3 popup for wallet" % account_name)
status_test_dapp.allow_button.click()
dapp.profile_button.click(desired_element_text='DApp permissions')
profile.element_by_text(test_dapp_name).click()
for text in 'Chat key', account_name:
if not dapp.element_by_text_part(text).is_element_displayed():
self.errors.append("Access is not granted to %s" % text)
home.just_fyi('check correct account is shown for transaction if sending from DApp')
profile.dapp_tab_button.click(desired_element_text='Accounts')
status_test_dapp.assets_button.click()
send_transaction = status_test_dapp.request_stt_button.click()
send_transaction.ok_got_it_button.wait_and_click()
address = send_transaction.get_formatted_recipient_address(address)
if not send_transaction.element_by_text(address).is_element_displayed():
self.errors.append("Wallet address %s in not shown in 'From' on Send Transaction screen" % address)
home.just_fyi('Relogin and check multiaccount loads fine')
send_transaction.cancel_button.click()
home.profile_button.click()
home.relogin()
home.wallet_button.click()
if not wallet.element_by_text(account_name).is_element_displayed():
self.errors.append("Subaccount is gone after relogin in Wallet!")
home.profile_button.click()
profile.privacy_and_security_button.click()
profile.dapp_permissions_button.click()
profile.element_by_text(test_dapp_name).click()
if not profile.element_by_text(account_name).is_element_displayed():
self.errors.append("Subaccount is not selected after relogin in Dapps!")
self.errors.verify_no_errors()
@@ -0,0 +1,65 @@
from selenium.common.exceptions import NoSuchElementException
from tests import marks, test_dapp_url
from tests.base_test_case import SingleDeviceTestCase
from tests.users import basic_user, ens_user
from views.sign_in_view import SignInView
class TestDeepLinks(SingleDeviceTestCase):
@marks.testrail_id(5441)
@marks.medium
def test_open_user_profile_using_deep_link(self):
sign_in = SignInView(self.driver)
sign_in.create_user()
for user_ident in ens_user['ens'], ens_user['ens_another'], ens_user['public_key']:
self.driver.close_app()
deep_link = 'status-im://u/%s' % user_ident
sign_in.open_weblink_and_login(deep_link)
chat = sign_in.get_chat_view()
for text in ens_user['username'], sign_in.get_translation_by_key("add-to-contacts"):
if not chat.element_by_text(text).scroll_to_element(10):
self.driver.fail("User profile screen is not opened")
@marks.testrail_id(5442)
@marks.medium
def test_open_dapp_using_deep_link(self):
sign_in_view = SignInView(self.driver)
sign_in_view.create_user()
self.driver.close_app()
dapp_name = test_dapp_url
dapp_deep_link = 'status-im://b/%s' % dapp_name
sign_in_view.open_weblink_and_login(dapp_deep_link)
web_view = sign_in_view.get_chat_view()
try:
test_dapp_view = web_view.open_in_status_button.click()
test_dapp_view.allow_button.is_element_present()
except NoSuchElementException:
self.driver.fail("DApp '%s' is not opened!" % dapp_name)
@marks.testrail_id(5781)
@marks.medium
def test_deep_link_with_invalid_user_public_key_own_profile_key(self):
sign_in = SignInView(self.driver)
sign_in.recover_access(passphrase=basic_user['passphrase'])
self.driver.close_app()
sign_in.just_fyi('Check that no error when opening invalid deep link')
deep_link = 'status-im://u/%s' % basic_user['public_key'][:-10]
sign_in.open_weblink_and_login(deep_link)
home = sign_in.get_home_view()
home.plus_button.click_until_presence_of_element(home.start_new_chat_button)
if not home.start_new_chat_button.is_element_present():
self.errors.append(
"Can't navigate to start new chat after app opened from deep link with invalid public key")
self.driver.close_app()
sign_in.just_fyi('Check that no error when opening invalid deep link')
deep_link = 'status-im://u/%s' % basic_user['public_key']
sign_in.open_weblink_and_login(deep_link)
from views.profile_view import ProfileView
profile = ProfileView(self.driver)
if not profile.default_username_text != basic_user['username']:
self.errors.append("Can't navigate to profile from deep link with own public key")
self.errors.verify_no_errors()
@@ -1,19 +1,20 @@
import random
from datetime import timedelta
from time import sleep
import emoji
import pytest
from dateutil import parser
from tests import marks, test_dapp_name, test_dapp_url
from tests.base_test_case import create_shared_drivers, MultipleSharedDeviceTestCase
from tests.base_test_case import MultipleDeviceTestCase, create_shared_drivers, \
MultipleSharedDeviceTestCase
from views.sign_in_view import SignInView
from selenium.common.exceptions import NoSuchElementException
@pytest.mark.xdist_group(name="public_chat_2")
@marks.critical
@pytest.mark.run2
class TestPublicChatMultipleDeviceMerged(MultipleSharedDeviceTestCase):
@classmethod
@@ -29,8 +30,7 @@ class TestPublicChatMultipleDeviceMerged(MultipleSharedDeviceTestCase):
cls.home_1.join_public_chat(cls.pub_chat_delete_long_press)
[home.home_button.click() for home in (cls.home_1, cls.home_2)]
cls.public_chat_name = cls.home_1.get_random_chat_name()
cls.chat_1 = cls.home_1.join_public_chat(cls.public_chat_name)
cls.chat_2 = cls.home_2.join_public_chat(cls.public_chat_name)
cls.chat_1, cls.chat_2 = cls.home_1.join_public_chat(cls.public_chat_name), cls.home_2.join_public_chat(cls.public_chat_name)
cls.chat_1.send_message(cls.text_message)
@marks.testrail_id(5313)
@@ -40,8 +40,7 @@ class TestPublicChatMultipleDeviceMerged(MultipleSharedDeviceTestCase):
sent_time_variants = self.chat_1.convert_device_time_to_chat_timestamp()
timestamp = self.chat_1.chat_element_by_text(message).timestamp_on_tap
if timestamp not in sent_time_variants:
self.errors.append("Timestamp is not shown, expected: '%s', in fact: '%s'" %
(sent_time_variants.join(','), timestamp))
self.errors.append("Timestamp is not shown, expected: '%s', in fact: '%s'" % (sent_time_variants.join(','), timestamp))
self.chat_2.home_button.click(desired_view='chat')
for chat in self.chat_1, self.chat_2:
chat.verify_message_is_under_today_text(message, self.errors)
@@ -161,7 +160,7 @@ class TestPublicChatMultipleDeviceMerged(MultipleSharedDeviceTestCase):
@marks.testrail_id(700737)
def test_public_chat_links_with_previews_github_youtube_twitter_gif_send_enable(self):
[chat.home_button.double_click() for chat in (self.chat_1, self.chat_2)]
[chat.get_back_to_home_view() for chat in (self.chat_1, self.chat_2)]
[home.get_chat('#' + self.public_chat_name).click() for home in (self.home_1, self.home_2)]
giphy_url = 'https://giphy.com/gifs/this-is-fine-QMHoU66sBXqqLqYvGO'
preview_urls = {'github_pr': {'url': 'https://github.com/status-im/status-react/pull/11707',
@@ -225,7 +224,6 @@ class TestPublicChatMultipleDeviceMerged(MultipleSharedDeviceTestCase):
@pytest.mark.xdist_group(name="public_chat_browser_1")
@marks.critical
@pytest.mark.run2
class TestPublicChatBrowserOneDeviceMerged(MultipleSharedDeviceTestCase):
@classmethod
@@ -289,41 +287,6 @@ class TestPublicChatBrowserOneDeviceMerged(MultipleSharedDeviceTestCase):
if not self.chat.chat_element_by_text(text_message).is_element_displayed(30):
self.drivers[0].fail("Not navigated to chat view after reopening app")
@marks.testrail_id(5317)
def test_public_chat_copy_and_paste_message_in_chat_input(self):
message_text = {'text_message': 'mmmeowesage_text'}
formatted_message = {'message_with_link': 'https://status.im',
# TODO: blocked with 11161 (rechecked 23.11.21, valid)
# 'message_with_tag': '#successishere'
}
message_input = self.chat.chat_message_input
if not message_input.is_element_displayed():
self.home.get_chat('#%s' % self.public_chat_name).click()
message_input.send_keys(message_text['text_message'])
self.chat.send_message_button.click()
self.chat.copy_message_text(message_text['text_message'])
message_input.paste_text_from_clipboard()
if message_input.text != message_text['text_message']:
self.errors.append('Message %s text was not copied in a public chat' % message_text['text_message'])
message_input.clear()
for message in formatted_message:
message_input.send_keys(formatted_message[message])
self.chat.send_message_button.click()
message_bubble = self.chat.chat_element_by_text(formatted_message[message])
message_bubble.sent_status_checkmark.long_press_element()
self.chat.element_by_text('Copy').click()
message_input.paste_text_from_clipboard()
if message_input.text != formatted_message[message]:
self.errors.append('Message %s text was not copied in a public chat' % formatted_message[message])
message_input.clear()
self.errors.verify_no_errors()
@marks.testrail_id(700738)
def test_public_chat_tag_message(self):
tag_message = '#wuuut'
@@ -350,7 +313,7 @@ class TestPublicChatBrowserOneDeviceMerged(MultipleSharedDeviceTestCase):
try:
assert self.chat.user_name_text.text == '#' + chat_name
except (AssertionError, NoSuchElementException):
self.drivers[0].fail("Public chat '%s' is not opened" % chat_name)
self.driver.fail("Public chat '%s' is not opened" % chat_name)
@marks.testrail_id(702072)
def test_browser_blocked_url(self):
@@ -509,3 +472,186 @@ class TestPublicChatBrowserOneDeviceMerged(MultipleSharedDeviceTestCase):
if not dapp.element_by_translation_id("your-contact-code").is_element_displayed():
self.errors.append('Profile permission is not asked')
self.errors.verify_no_errors()
class TestPublicChatMultipleDevice(MultipleDeviceTestCase):
@marks.testrail_id(6342)
@marks.medium
def test_different_status_in_timeline(self):
self.create_drivers(2)
device_1, device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
home_1, home_2 = device_1.create_user(), device_2.create_user()
profile_1, profile_2 = home_1.profile_button.click(), home_2.profile_button.click()
public_key_1, username_1 = profile_1.get_public_key_and_username(return_username=True)
emoji_message = random.choice(list(emoji.EMOJI_UNICODE))
emoji_unicode = emoji.EMOJI_UNICODE[emoji_message]
home_1.just_fyi('Set status in profile')
statuses = {
'*formatted text*': 'formatted text',
'https://www.youtube.com/watch?v=JjPWmEh2KhA': 'Status Town Hall',
emoji.emojize(emoji_message): emoji_unicode,
}
timeline_1 = device_1.status_button.click()
for status in statuses.keys():
timeline_1.set_new_status(status)
sleep(60)
timeline_1.element_by_translation_id("enable").wait_and_click()
timeline_1.element_by_translation_id("enable-all").wait_and_click()
timeline_1.close_modal_view_from_chat_button.click()
for status in statuses:
expected_value = statuses[status]
if not timeline_1.element_by_text_part(expected_value).is_element_displayed():
self.errors.append("Expected value %s is not shown" % expected_value)
text_status = 'some text'
timeline_1.set_new_status(status=text_status)
for timestamp in ('Now', '1M', '2M'):
if not timeline_1.element_by_text(timestamp).is_element_displayed():
self.errors.append("Expected timestamp %s is not shown in timeline_1" % timestamp)
home_2.just_fyi('Check that can see user status without adding him as contact')
profile_2.home_button.click()
chat_2 = home_2.add_contact(public_key_1, add_in_contacts=False)
chat_2.chat_options.click()
chat_2.view_profile_button.click()
chat_2.chat_element_by_text(text_status).wait_for_element(30)
chat_2.element_by_translation_id("enable").scroll_and_click()
chat_2.element_by_translation_id("enable-all").wait_and_click()
chat_2.close_modal_view_from_chat_button.click()
for status in statuses:
chat_2.element_by_text_part(statuses['*formatted text*']).scroll_to_element()
expected_value = statuses[status]
if not chat_2.element_by_text_part(expected_value).is_element_displayed():
self.errors.append(
"Expected value %s is not shown in other user profile without adding to contacts" % expected_value)
home_2.just_fyi('Add device1 to contacts and check that status will be shown in timeline_1')
chat_2.close_button.scroll_and_click(direction='up')
chat_2.add_to_contacts.click()
timeline_2 = chat_2.status_button.click()
for status in statuses:
expected_value = statuses[status]
if not timeline_2.element_by_text_part(expected_value).is_element_displayed():
self.errors.append(
"Expected value %s is not shown in timeline_1 after adding user to contacts" % expected_value)
profile_1.just_fyi('Checking message tag and reactions on statuses')
tag_status = '#public-chat-to-redirect-long-name'
timeline_1.set_new_status(tag_status)
public_chat_2 = home_2.get_chat_view()
public_chat_2.element_by_text(tag_status).wait_and_click()
public_chat_2.user_name_text.wait_for_element(30)
if not public_chat_2.user_name_text.text == tag_status:
self.errors.append('Could not redirect a user to a public chat tapping the tag message from timeline_1')
public_chat_2.back_button.click()
timeline_1.set_reaction(text_status)
status_with_reaction_1 = timeline_1.chat_element_by_text(text_status)
if status_with_reaction_1.emojis_below_message() != 1:
self.errors.append("Counter of reaction is not updated on your own status in timeline_1!")
device_2.home_button.double_click()
home_2.get_chat(username_1).click()
chat_2.chat_options.click()
chat_2.view_profile_button.click()
status_with_reaction_2 = chat_2.chat_element_by_text(text_status)
if status_with_reaction_2.emojis_below_message(own=False) != 1:
self.errors.append("Counter of reaction is not updated on status of another user in profile!")
profile_1.just_fyi("Remove reaction and check it is updated for both users")
timeline_1.set_reaction(text_status)
status_with_reaction_1 = timeline_1.chat_element_by_text(text_status)
if status_with_reaction_1.emojis_below_message() != 0:
self.errors.append(
"Counter of reaction is not updated after removing reaction on your own status in timeline_1!")
status_with_reaction_2 = chat_2.chat_element_by_text(text_status)
if status_with_reaction_2.emojis_below_message(own=False) != 0:
self.errors.append(
"Counter of reaction is not updated after removing on status of another user in profile!")
profile_1.just_fyi("Remove user from contacts and check there is no his status in timeline_1 anymore")
chat_2.remove_from_contacts.click()
chat_2.close_button.click()
chat_2.status_button.click()
if public_chat_2.chat_element_by_text(text_status).is_element_displayed(10):
self.errors.append("Statuses of removed user are still shown in profile")
self.errors.verify_no_errors()
@marks.testrail_id(700727)
@marks.medium
def test_gap_in_public_chat_and_no_gap_in_1_1_and_group_chats(self):
self.create_drivers(2)
device_1, device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
home_1, home_2 = device_1.create_user(), device_2.create_user()
message_1 = "testing gap"
message_2 = "testing no gap"
pub_chat_name = home_1.get_random_chat_name()
group_chat_name = home_1.get_random_chat_name()
public_key_1, username_1 = home_1.get_public_key_and_username(True)
public_key_2, username_2 = home_2.get_public_key_and_username(True)
profile_1 = home_1.profile_button.click()
profile_1.sync_settings_button.click()
profile_1.sync_history_for_button.click()
profile_1.element_by_translation_id("two-minutes").click()
[home.home_button.click() for home in (home_1, home_2)]
home_1.just_fyi("Creating 1-1 chat and sending message from device 1")
one_to_one_chat_1 = home_1.add_contact(public_key_2)
one_to_one_chat_1.send_message("HI")
home_1.get_back_to_home_view()
home_1.just_fyi("Creating group chat and sending message from device 1")
group_chat_1 = home_1.create_group_chat([username_2], group_chat_name)
group_chat_1.send_message("HI")
home_1.get_back_to_home_view()
home_1.just_fyi("Creating public chat and sending message from device 1")
pub_chat_1, pub_chat_2 = home_1.join_public_chat(pub_chat_name), home_2.join_public_chat(pub_chat_name)
pub_chat_1.send_message("HI")
device_1.toggle_airplane_mode()
home_2.just_fyi("Joining public chat by device 2 and sending message")
pub_chat_2.send_message(message_1)
home_2.get_back_to_home_view()
home_2.just_fyi("Joining 1-1 chat by device 2 and sending message")
# one_to_one_chat_element = home_2.get_chat(username_1, wait_time=10)
# one_to_one_chat_2 = one_to_one_chat_element.click()
one_to_one_chat_2 = home_2.add_contact(public_key_1)
one_to_one_chat_2.send_message(message_2)
home_2.get_back_to_home_view()
home_2.just_fyi("Joining Group chat by device 2 and sending message")
# home_2.notifications_button.click()
# group_chat_2 = home_2.get_chat_from_activity_center_view(group_chat_name).click()
group_chat_2 = home_2.get_chat(group_chat_name).click()
group_chat_2.join_chat_button.click()
group_chat_2.send_message(message_2)
# Waiting for 3 minutes and then going back online
sleep(180)
device_1.toggle_airplane_mode()
home_1.just_fyi("Checking gap in public chat and fetching messages")
if pub_chat_1.chat_element_by_text(message_1).is_element_displayed(10):
self.errors.append("Test message has been fetched automatically")
pub_chat_1.element_by_translation_id("fetch-messages").wait_and_click(60)
if not pub_chat_1.chat_element_by_text(message_1).is_element_displayed(10):
self.errors.append("Test message has not been fetched")
home_1.get_back_to_home_view()
home_1.just_fyi("Checking that there is no gap in 1-1/group chat and messages fetched automatically")
for chat in [home_1.get_chat(username_2), home_1.get_chat(group_chat_name)]:
chat_view = chat.click()
if chat_view.element_by_translation_id("fetch-messages").is_element_displayed(10):
self.errors.append("Fetch messages button is displayed in {}} chat".format(chat.user_name_text.text))
if not chat_view.chat_element_by_text(message_2).is_element_displayed(10):
self.errors.append("Message in {} chat has not been fetched automatically".format(chat.user_name_text.text))
chat_view.back_button.click()
self.errors.verify_no_errors()
@@ -3,10 +3,10 @@ from tests import marks, pytest_config_global, test_dapp_name, staging_fleet, ma
from tests.base_test_case import SingleDeviceTestCase, MultipleDeviceTestCase
from tests.users import upgrade_users, transaction_recipients, basic_user, ens_user, transaction_senders
from views.sign_in_view import SignInView
import views.dbs.chats.data as chat_data
import views.dbs.dapps.data as dapp_data
import views.dbs.pairing.data as sync_data
import views.dbs.group.data as group
import views.upgrade_dbs.chats.data as chat_data
import views.upgrade_dbs.dapps.data as dapp_data
import views.upgrade_dbs.pairing.data as sync_data
import views.upgrade_dbs.group.data as group
@marks.upgrade
@@ -18,8 +18,7 @@ class TestUpgradeApplication(SingleDeviceTestCase):
sign_in = SignInView(self.driver)
unread_one_to_one_name, unread_public_name = 'All Whopping Dassierat', '#before-upgrade'
chats = chat_data.chats
seed = upgrade_users['chats']['passphrase']
home = sign_in.import_db(seed_phrase=seed, import_db_folder_name='chats')
home = sign_in.import_db(user=upgrade_users['chats'], import_db_folder_name='chats')
home.just_fyi("Grab profile version")
profile = home.profile_button.click()
@@ -142,8 +141,7 @@ class TestUpgradeApplication(SingleDeviceTestCase):
def test_dapps_browser_several_accounts_upgrade(self):
sign_in = SignInView(self.driver)
favourites = dapp_data.dapps['favourites']
seed = transaction_recipients['K']['passphrase']
home = sign_in.import_db(seed_phrase=seed, import_db_folder_name='dapps')
home = sign_in.import_db(user=transaction_recipients['K'], import_db_folder_name='dapps')
home.upgrade_app()
sign_in.sign_in()
dapps = home.dapp_tab_button.click()
@@ -256,10 +254,9 @@ class TestUpgradeMultipleApplication(MultipleDeviceTestCase):
device_2_public_key = device_2_home.get_public_key_and_username()
device_2_home.home_button.click()
user = upgrade_users['chats']
seed = user['passphrase']
device_1.just_fyi("Import db, upgrade")
home = device_1.import_db(seed_phrase=seed, import_db_folder_name='chats')
home = device_1.import_db(user=user, import_db_folder_name='chats')
home.upgrade_app()
home = device_1.sign_in()
@@ -313,9 +310,8 @@ class TestUpgradeMultipleApplication(MultipleDeviceTestCase):
device_1, device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
device_1.just_fyi("Import db, upgrade")
seed = user['passphrase']
home_1 = device_1.import_db(seed_phrase=seed, import_db_folder_name='pairing/main')
home_2 = device_2.import_db(seed_phrase=seed, import_db_folder_name='pairing/secondary')
home_1 = device_1.import_db(user=user, import_db_folder_name='pairing/main')
home_2 = device_2.import_db(user=user, import_db_folder_name='pairing/secondary')
for device in (device_1, device_2):
device.upgrade_app()
device.sign_in()
@@ -401,8 +397,8 @@ class TestUpgradeMultipleApplication(MultipleDeviceTestCase):
device_1, device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
device_1.just_fyi("Import db, upgrade")
home_1 = device_1.import_db(seed_phrase=admin['passphrase'], import_db_folder_name='group/admin')
home_2 = device_2.import_db(seed_phrase=member['passphrase'], import_db_folder_name='group/member')
home_1 = device_1.import_db(user=admin, import_db_folder_name='group/admin')
home_2 = device_2.import_db(user=member, import_db_folder_name='group/member')
for device in (device_1, device_2):
device.upgrade_app()
device.sign_in()
@@ -489,7 +485,7 @@ class TestUpgradeMultipleApplication(MultipleDeviceTestCase):
device_1, device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
device_1.just_fyi("Import db")
home_1 = device_1.import_db(seed_phrase=user['passphrase'], import_db_folder_name='group/admin')
home_1 = device_1.import_db(user=user, import_db_folder_name='group/admin')
home_2 = device_2.create_user()
profile_2 = home_2.profile_button.click()
public_key_2, username_2 = profile_2.get_public_key_and_username(return_username=True)
@@ -0,0 +1,341 @@
import pytest
from support.utilities import get_merged_txs_list
from tests import marks, pin, puk, pair_code
from tests.base_test_case import SingleDeviceTestCase, MultipleSharedDeviceTestCase, create_shared_drivers
from tests.users import transaction_senders, basic_user, wallet_users
from views.sign_in_view import SignInView
@pytest.mark.xdist_group(name="keycard_tx_1")
@marks.critical
class TestKeycardTxOneDeviceMerged(MultipleSharedDeviceTestCase):
@classmethod
def setup_class(cls):
cls.user = transaction_senders['ETH_STT_ADI_1']
cls.address = '0x%s' % transaction_senders['ETH_7']['address']
cls.drivers, cls.loop = create_shared_drivers(1)
cls.sign_in = SignInView(cls.drivers[0])
cls.home = cls.sign_in.recover_access(passphrase=cls.user['passphrase'], keycard=True)
cls.wallet = cls.home.wallet_button.click()
cls.assets = ('ETH', 'ADI', 'STT')
[cls.wallet.wait_balance_is_changed(asset) for asset in cls.assets]
cls.initial_balances = dict()
for asset in cls.assets:
cls.initial_balances[asset] = cls.wallet.get_asset_amount_by_name(asset)
@marks.testrail_id(700767)
def test_keycard_send_tx_eth(self):
wallet = self.home.wallet_button.click()
transaction_amount = wallet.get_unique_amount()
wallet.send_transaction(amount=transaction_amount, sign_transaction=True, keycard=True,
recipient=self.address)
wallet.just_fyi('Check that transaction is appeared in transaction history')
transaction = wallet.find_transaction_in_history(amount=transaction_amount, return_hash=True)
self.wallet.wallet_button.double_click()
self.network_api.find_transaction_by_hash(transaction)
self.network_api.wait_for_confirmation_of_transaction(self.user['address'], transaction_amount)
self.wallet.wait_balance_is_changed('ETH', initial_balance=self.initial_balances['ETH'])
@marks.testrail_id(700768)
def test_keycard_relogin_after_restore(self):
self.sign_in.just_fyi('Check that username and public key match expected')
public_key, default_username = self.sign_in.get_public_key_and_username(return_username=True)
profile = self.sign_in.get_profile_view()
if public_key != self.user['public_key']:
self.errors.append('Public key %s does not match expected' % public_key)
if default_username != self.user['username']:
self.errors.append('Default username %s does not match expected' % default_username)
profile.logout()
self.sign_in.just_fyi('Check that can login with restored from mnemonic keycard account')
self.sign_in.sign_in(keycard=True)
if not self.sign_in.home_button.is_element_displayed(10):
self.sign_in.driver.fail('Keycard user is not logged in')
self.errors.verify_no_errors()
@marks.testrail_id(700769)
@marks.transaction
def test_keycard_send_tx_sign_message_request_stt_testdapp(self):
self.home.home_button.double_click()
status_test_dapp = self.home.open_status_test_dapp()
status_test_dapp.wait_for_d_aap_to_load()
self.wallet.just_fyi("Requesting STT in dapp")
status_test_dapp.assets_button.click()
send_tx = status_test_dapp.request_stt_button.click()
send_tx.sign_transaction(keycard=True)
self.wallet.just_fyi("Checking signing message")
status_test_dapp.transactions_button.click()
status_test_dapp.sign_message_button.click()
if not send_tx.element_by_text("Test message").is_element_displayed():
self.errors.append("No message shown when signing!")
keycard = send_tx.sign_with_keycard_button.click()
keycard.enter_default_pin()
if not keycard.element_by_text_part('Signed message').is_element_displayed():
self.errors.append('Message was not signed')
keycard.just_fyi('Check logcat for sensitive data')
values_in_logcat = send_tx.find_values_in_logcat(pin=pin, puk=puk, password=pair_code)
if values_in_logcat:
self.sign_in.driver.fail("After signing message: %s" % values_in_logcat)
self.wallet.just_fyi("Check send 2 txs in batch")
status_test_dapp.send_two_tx_in_batch_button.scroll_to_element()
send_tx = status_test_dapp.send_two_tx_in_batch_button.click()
send_tx.sign_transaction(keycard=True)
if not send_tx.sign_with_keycard_button.is_element_displayed(10):
self.sign_in.driver.fail('Second send transaction screen did not appear!')
send_tx.sign_transaction(keycard=True)
self.wallet.just_fyi("Checking send 2 txs one after another")
status_test_dapp.send_two_tx_one_by_one_button.scroll_to_element()
send_tx = status_test_dapp.send_two_tx_one_by_one_button.click()
send_tx.sign_transaction(keycard=True)
if not send_tx.sign_with_keycard_button.is_element_displayed(20):
self.sign_in.driver.fail('Second send transaction screen did not appear!')
send_tx.sign_transaction(keycard=True)
self.wallet.just_fyi('Verify that wallet balance is updated after receiving money from faucet')
self.home.wallet_button.click()
self.wallet.wait_balance_is_changed('STT', initial_balance=self.initial_balances['STT'])
self.errors.verify_no_errors()
@marks.testrail_id(700770)
def test_keycard_wallet_recover_pairing_check_balance_after_offline_tx_history(self):
user = transaction_senders['A']
self.sign_in.toggle_airplane_mode()
self.sign_in.driver.reset()
self.sign_in.just_fyi('Keycard: recover multiaccount with pairing code ')
self.sign_in.accept_tos_checkbox.enable()
self.sign_in.get_started_button.click_until_presence_of_element(self.sign_in.access_key_button)
self.sign_in.access_key_button.click()
self.sign_in.recover_with_keycard_button.click()
keycard = self.sign_in.begin_recovery_button.click()
keycard.connect_pairing_card_button.click()
keycard.pair_code_input.set_value(pair_code)
self.sign_in.pair_to_this_device_button.click()
keycard.enter_default_pin()
self.sign_in.maybe_later_button.click_until_presence_of_element(self.sign_in.lets_go_button)
self.sign_in.lets_go_button.click_until_absense_of_element(self.sign_in.lets_go_button)
self.sign_in.home_button.wait_for_visibility_of_element(30)
self.sign_in.just_fyi("Check balance will be restored after going back online")
self.sign_in.toggle_airplane_mode()
wallet = self.home.wallet_button.click()
[wallet.wait_balance_is_changed(asset) for asset in ("ETH", "LXS")]
self.wallet.just_fyi("Checking whole tx history after backing from offline")
self.wallet.accounts_status_account.click()
address = user['address']
ropsten_txs = self.network_api.get_transactions(address)
ropsten_tokens = self.network_api.get_token_transactions(address)
expected_txs_list = get_merged_txs_list(ropsten_txs, ropsten_tokens)
transactions = self.wallet.transaction_history_button.click()
if self.wallet.element_by_translation_id("transactions-history-empty").is_element_displayed():
self.wallet.pull_to_refresh()
status_tx_number = transactions.transactions_table.get_transactions_number()
if status_tx_number < 1:
self.errors.append('No transactions found')
for n in range(status_tx_number):
transactions_details = transactions.transactions_table.transaction_by_index(n).click()
tx_hash = transactions_details.get_transaction_hash()
tx_from = transactions_details.get_sender_address()
tx_to = transactions_details.get_recipient_address()
if tx_from != expected_txs_list[tx_hash]['from']:
self.errors.append('Transactions senders do not match!')
if tx_to != expected_txs_list[tx_hash]['to']:
self.errors.append('Transactions recipients do not match!')
transactions_details.close_button.click()
self.errors.verify_no_errors()
@marks.testrail_id(5689)
def test_keycard_create_account_unlock_same_seed(self):
self.sign_in.driver.reset()
self.sign_in.just_fyi("Create keycard account and save seed phrase")
self.sign_in.accept_tos_checkbox.enable()
self.sign_in.get_started_button.click()
self.sign_in.generate_key_button.click_until_presence_of_element(self.sign_in.next_button)
self.sign_in.next_button.click_until_absense_of_element(self.sign_in.element_by_translation_id("intro-wizard-title2"))
keycard_flow = self.sign_in.keycard_storage_button.click()
keycard_flow.confirm_pin_and_proceed()
seed_phrase = keycard_flow.backup_seed_phrase()
self.sign_in.maybe_later_button.wait_for_visibility_of_element(30)
self.sign_in.maybe_later_button.click_until_presence_of_element(self.sign_in.lets_go_button)
self.sign_in.lets_go_button.click_until_absense_of_element(self.sign_in.lets_go_button)
self.sign_in.profile_button.wait_for_visibility_of_element(30)
self.sign_in.just_fyi('Check that after creating keycard account balance is 0, not ...')
wallet_1 = self.sign_in.wallet_button.click()
wallet_address = wallet_1.get_wallet_address()
wallet_1.wallet_button.double_click()
if wallet_1.status_account_total_usd_value.text != '0':
self.errors.append("Account USD value is not 0, it is %s" % wallet_1.status_account_total_usd_value.text)
public_key, default_username = self.sign_in.get_public_key_and_username(return_username=True)
profile_1 = self.sign_in.get_profile_view()
profile_1.logout()
profile_1.just_fyi('Check that can re-login with keycard account after account creation')
self.sign_in.multi_account_on_login_button.wait_for_visibility_of_element(5)
self.sign_in.multi_account_on_login_button.click()
if not keycard_flow.element_by_text_part(default_username).is_element_displayed():
self.errors.append("%s is not found on keycard login screen!" % default_username)
keycard_flow.enter_default_pin()
if not self.sign_in.home_button.is_element_displayed(10):
self.errors.append('Keycard user is not logged in')
self.sign_in.just_fyi('Unlock keycard multiaccount at attempt to restore same multiaccount from seed')
self.sign_in.profile_button.click()
profile_1.logout()
self.sign_in.access_key_button.click()
self.sign_in.enter_seed_phrase_button.click()
self.sign_in.seedphrase_input.click()
self.sign_in.seedphrase_input.set_value(seed_phrase)
self.sign_in.next_button.click()
self.sign_in.element_by_translation_id("unlock", uppercase=True).click()
keycard_flow.enter_default_pin()
device_1_home = self.sign_in.home_button.click()
device_1_home.plus_button.click()
if not device_1_home.start_new_chat_button.is_element_displayed():
self.errors.append("Can't proceed using account after it's re-recover twice.")
self.sign_in.just_fyi("Restore same multiaccount from backed up seed phrase on another device")
self.sign_in.driver.reset()
self.sign_in.recover_access(seed_phrase)
self.sign_in.just_fyi("Check username and wallet address on restored account")
wallet_2 = self.sign_in.wallet_button.click()
wallet_address_2 = wallet_2.get_wallet_address()
wallet_2.wallet_button.double_click()
if wallet_address != wallet_address_2:
self.errors.append('Wallet address on restored multiaccount is not equal to created keycard multiaccount')
public_key_2, default_username_2 = self.sign_in.get_public_key_and_username(return_username=True)
if public_key != public_key_2:
self.errors.append('Public key on restored multiaccount is not equal to created keycard multiaccount')
if default_username_2 != default_username:
self.errors.append('Username on restored multiaccount is not equal to created keycard multiaccount')
self.errors.verify_no_errors()
class TestTransactionWalletSingleDevice(SingleDeviceTestCase):
@marks.testrail_id(6292)
@marks.transaction
@marks.medium
def test_keycard_send_funds_between_accounts_set_max_in_multiaccount_instance(self):
sign_in_view = SignInView(self.driver).create_user(keycard=True)
wallet = sign_in_view.wallet_button.click()
status_account_address = wallet.get_wallet_address()[2:]
self.network_api.get_donate(status_account_address, external_faucet=True)
wallet.wait_balance_is_changed()
account_name = 'subaccount'
wallet.add_account(account_name, keycard=True)
wallet.get_account_by_name(account_name).click()
wallet.get_account_options_by_name(account_name).click()
wallet.account_settings_button.click()
wallet.swipe_up()
wallet.just_fyi("Checking that delete account and importing account are not available on keycard")
if wallet.delete_account_button.is_element_displayed(10):
self.errors.append('Delete account option is shown on added account "On Status Tree"!')
wallet.wallet_button.double_click()
wallet.add_account_button.click()
if wallet.enter_a_seed_phrase_button.is_element_displayed():
self.errors.append('Importing account option is available on keycard!')
wallet.click_system_back_button()
wallet.just_fyi("Send transaction to new account")
transaction_amount = '0.004'
initial_balance = self.network_api.get_balance(status_account_address)
wallet.send_transaction(account_name=account_name, amount=transaction_amount, keycard=True)
self.network_api.wait_for_confirmation_of_transaction(status_account_address, transaction_amount)
self.network_api.verify_balance_is_updated(str(initial_balance), status_account_address)
wallet.just_fyi("Verifying previously sent transaction in new account")
wallet.get_account_by_name(account_name).click()
wallet.send_transaction_button.click()
wallet.close_send_transaction_view_button.click()
balance_after_receiving_tx = float(wallet.get_asset_amount_by_name('ETH'))
expected_balance = self.network_api.get_rounded_balance(balance_after_receiving_tx, transaction_amount)
if balance_after_receiving_tx != expected_balance:
self.driver.fail('New account balance %s does not match expected %s after receiving a transaction' % (
balance_after_receiving_tx, transaction_amount))
wallet.just_fyi("Sending eth from new account to main account")
updated_balance = self.network_api.get_balance(status_account_address)
transaction_amount_1 = round(float(transaction_amount) * 0.2, 11)
wallet.wait_balance_is_changed()
wallet.get_account_by_name(account_name).click()
send_transaction = wallet.send_transaction(from_main_wallet=False, account_name=wallet.status_account_name,
amount=transaction_amount_1, keycard=True)
wallet.close_button.click()
sub_account_address = wallet.get_wallet_address(account_name)[2:]
self.network_api.wait_for_confirmation_of_transaction(sub_account_address, transaction_amount_1)
wallet.find_transaction_in_history(amount=format(float(transaction_amount_1), '.11f').rstrip('0'))
wallet.just_fyi("Check transactions on subaccount")
self.network_api.verify_balance_is_updated(updated_balance, status_account_address)
wallet.just_fyi("Verify total ETH on main wallet view")
self.network_api.wait_for_confirmation_of_transaction(status_account_address, transaction_amount_1)
self.network_api.verify_balance_is_updated((updated_balance + transaction_amount_1), status_account_address)
wallet.close_button.click()
balance_of_sub_account = float(self.network_api.get_balance(sub_account_address)) / 1000000000000000000
balance_of_status_account = float(self.network_api.get_balance(status_account_address)) / 1000000000000000000
wallet.scan_tokens()
total_eth_from_two_accounts = float(wallet.get_asset_amount_by_name('ETH'))
expected_balance = self.network_api.get_rounded_balance(total_eth_from_two_accounts,
(balance_of_status_account + balance_of_sub_account))
if total_eth_from_two_accounts != expected_balance:
self.driver.fail('Total wallet balance %s != of Status account (%s) + SubAccount (%s)' % (
total_eth_from_two_accounts, balance_of_status_account, balance_of_sub_account))
wallet.just_fyi("Check that can set max and send transaction with max amount from subaccount")
wallet.get_account_by_name(account_name).click()
wallet.send_transaction_button.click()
send_transaction.set_max_button.click()
set_amount = float(send_transaction.amount_edit_box.text)
if set_amount == 0.0 or set_amount >= balance_of_sub_account:
self.driver.fail('Value after setting up max amount is set to %s' % str(set_amount))
send_transaction.confirm()
send_transaction.chose_recipient_button.click()
send_transaction.accounts_button.click()
send_transaction.element_by_text(wallet.status_account_name).click()
send_transaction.sign_transaction_button.click()
send_transaction.sign_transaction(keycard=True)
wallet.element_by_text('Assets').click()
wallet.wait_balance_is_equal_expected_amount(asset='ETH', expected_balance=0, main_screen=False)
@marks.testrail_id(6310)
@marks.medium
@marks.transaction
def test_keycard_sign_typed_message_deploy_simple_contract(self):
sender = transaction_senders['ETH_6']
home = SignInView(self.driver).recover_access(sender['passphrase'], keycard=True)
wallet = home.wallet_button.click()
status_test_dapp = home.open_status_test_dapp()
status_test_dapp.wait_for_d_aap_to_load()
status_test_dapp.transactions_button.click_until_presence_of_element(status_test_dapp.sign_typed_message_button)
wallet.just_fyi("Checking sign typed message")
send_transaction = status_test_dapp.sign_typed_message_button.click()
send_transaction.sign_with_keycard_button.click()
keycard_view = send_transaction.sign_with_keycard_button.click()
keycard_view.enter_default_pin()
if not keycard_view.element_by_text_part('0x6df0ce').is_element_displayed():
self.errors.append('Typed message was not signed')
wallet.just_fyi("Checking deploy simple contract")
send_transaction_view = status_test_dapp.deploy_contract_button.click()
send_transaction_view.sign_transaction(keycard=True)
if not status_test_dapp.element_by_text('Contract deployed at: ').is_element_displayed(300):
self.driver.fail('Contract was not created or tx taking too long')
for text in ['Call contract get function',
'Call contract set function', 'Call function 2 times in a row']:
status_test_dapp.element_by_text(text).scroll_to_element()
self.errors.verify_no_errors()
@@ -0,0 +1,795 @@
import random
import string
import pytest
from tests import marks, common_password
from tests.base_test_case import SingleDeviceTestCase, MultipleDeviceTestCase, MultipleSharedDeviceTestCase,\
create_shared_drivers
from tests.users import transaction_senders, basic_user, wallet_users, ens_user_ropsten, ens_user
from views.send_transaction_view import SendTransactionView
from views.sign_in_view import SignInView
@pytest.mark.xdist_group(name="send_tx_1")
@marks.critical
class TestSendTxDeviceMerged(MultipleSharedDeviceTestCase):
@classmethod
def setup_class(cls):
cls.user = transaction_senders['ETH_ADI_STT_3']
cls.recipient_address = '0x%s' % transaction_senders['ETH_7']['address']
cls.drivers, cls.loop = create_shared_drivers(1)
[cls.amount_adi, cls.amount_eth, cls.amount_stt] = ['0.000%s' % str(random.randint(100, 999)) + '1' for _ in range(3)]
cls.sign_in = SignInView(cls.drivers[0])
cls.home = cls.sign_in.recover_access(cls.user['passphrase'])
cls.wallet = cls.home.wallet_button.click()
cls.assets = ('ETH', 'ADI', 'STT')
[cls.wallet.wait_balance_is_changed(asset) for asset in cls.assets]
cls.initial_balances = dict()
for asset in cls.assets:
cls.initial_balances[asset] = cls.wallet.get_asset_amount_by_name(asset)
cls.wallet.send_transaction(amount=cls.amount_eth, recipient=cls.recipient_address)
cls.wallet.send_transaction(amount=cls.amount_adi, recipient=cls.recipient_address, asset_name='ADI')
@marks.testrail_id(700763)
@marks.transaction
def test_send_tx_eth_check_logcat(self):
self.wallet.just_fyi('Check that transaction is appeared in tx history')
self.wallet.find_transaction_in_history(amount=self.amount_eth)
self.wallet.wallet_button.double_click()
self.network_api.wait_for_confirmation_of_transaction(self.user['address'], self.amount_eth)
self.wallet.wait_balance_is_changed('ETH', initial_balance=self.initial_balances['ETH'])
self.wallet.just_fyi('Check logcat for sensitive data')
values_in_logcat = self.wallet.find_values_in_logcat(password=common_password)
if values_in_logcat:
self.wallet.driver.fail(values_in_logcat)
@marks.testrail_id(700764)
@marks.transaction
def test_send_tx_token_7_decimals(self):
asset = 'ADI'
self.wallet.just_fyi("Checking tx with 7 decimals")
transaction_adi = self.wallet.find_transaction_in_history(amount=self.amount_adi, asset=asset, return_hash=True)
self.wallet.wallet_button.double_click()
self.network_api.find_transaction_by_hash(transaction_adi)
self.wallet.wait_balance_is_changed(asset, initial_balance=self.initial_balances[asset])
@marks.testrail_id(5342)
@marks.transaction
def test_send_tx_sign_message_2tx_in_batch_tx_filters_request_stt_testdapp(self):
self.wallet.home_button.click()
status_test_dapp = self.home.open_status_test_dapp()
status_test_dapp.wait_for_d_aap_to_load()
self.wallet.just_fyi("Checking request STT")
status_test_dapp.assets_button.click()
status_test_dapp.request_stt_button.wait_for_element(60)
send_transaction = status_test_dapp.request_stt_button.click()
send_transaction.sign_transaction()
self.wallet.just_fyi("Checking signing message")
status_test_dapp.transactions_button.click()
send_transaction = status_test_dapp.sign_message_button.click()
send_transaction.enter_password_input.set_value(common_password)
send_transaction.sign_button.click()
if not status_test_dapp.element_by_text_part('Signed message').is_element_displayed():
self.errors.append('Message was not signed')
send_transaction.just_fyi('Check logcat for sensitive data')
values_in_logcat = send_transaction.find_values_in_logcat(password=common_password)
if values_in_logcat:
self.errors.append("When signing message from dapp: %s" % values_in_logcat)
self.wallet.just_fyi("Checking send 2 txs in batch")
status_test_dapp.send_two_tx_in_batch_button.scroll_to_element()
send_transaction = status_test_dapp.send_two_tx_in_batch_button.click()
send_transaction.sign_transaction()
if not send_transaction.sign_with_password.is_element_displayed(10):
self.errors.append('Second send transaction screen did not appear!')
send_transaction.sign_transaction()
self.wallet.just_fyi("Checking send 2 txs one after another")
status_test_dapp.send_two_tx_one_by_one_button.scroll_to_element()
send_transaction = status_test_dapp.send_two_tx_one_by_one_button.click()
send_transaction.sign_transaction()
if not send_transaction.sign_with_password.is_element_displayed(20):
self.errors.append('Second send transaction screen did not appear!')
send_transaction.sign_transaction()
self.wallet.just_fyi("Checking test filters")
status_test_dapp.test_filters_button.scroll_and_click()
for element in status_test_dapp.element_by_text('eth_uninstallFilter'), status_test_dapp.ok_button:
if element.is_element_displayed(10):
self.errors.append("'Test filters' button produced an error")
self.errors.verify_no_errors()
@marks.testrail_id(700765)
@marks.transaction
def test_send_tx_custom_token_18_decimals_invalid_password(self):
contract_address, name, symbol, decimals = '0x101848D5C5bBca18E6b4431eEdF6B95E9ADF82FA', 'Weenus 💪', 'WEENUS', '18'
self.home.wallet_button.double_click()
self.wallet.just_fyi("Check that can add custom token")
self.wallet.multiaccount_more_options.click()
self.wallet.manage_assets_button.click()
token_view = self.wallet.add_custom_token_button.click()
token_view.contract_address_input.send_keys(contract_address)
if token_view.name_input.text != name:
self.errors.append('Name for custom token was not set')
if token_view.symbol_input.text != symbol:
self.errors.append('Symbol for custom token was not set')
if token_view.decimals_input.text != decimals:
self.errors.append('Decimals for custom token was not set')
token_view.add_button.click()
token_view.close_button.click()
self.wallet.asset_by_name(symbol).scroll_to_element()
if not self.wallet.asset_by_name(symbol).is_element_displayed():
self.errors.append('Custom token is not shown on Wallet view')
send_tx = self.wallet.send_transaction_from_main_screen.click()
send_tx.select_asset_button.click()
asset_button = send_tx.asset_by_name(symbol)
send_tx.select_asset_button.click_until_presence_of_element(
send_tx.eth_asset_in_select_asset_bottom_sheet_button)
asset_button.click()
send_tx.amount_edit_box.click()
send_tx.amount_edit_box.set_value(self.amount_eth)
send_tx.set_recipient_address(self.recipient_address)
send_tx.sign_transaction_button.click()
if self.wallet.sign_in_phrase.is_element_displayed():
self.wallet.set_up_wallet_when_sending_tx()
send_tx.just_fyi('Check that can not sign tx with invalid password')
self.wallet.next_button.click_if_shown()
self.wallet.ok_got_it_button.click_if_shown()
send_tx.sign_with_password.click_until_presence_of_element(send_tx.enter_password_input)
send_tx.enter_password_input.click()
send_tx.enter_password_input.send_keys('wrong_password')
send_tx.sign_button.click()
if send_tx.element_by_text_part('Transaction sent').is_element_displayed():
self.errors.append('Transaction was sent with a wrong password')
self.wallet.just_fyi("Check that can send tx with custom token")
send_tx.enter_password_input.click()
send_tx.enter_password_input.clear()
send_tx.enter_password_input.send_keys(common_password)
send_tx.sign_button.click_until_absense_of_element(send_tx.sign_button)
send_tx.ok_button.wait_for_element(120)
if not self.wallet.element_by_translation_id("transaction-sent").is_element_displayed():
self.errors.append("Tx is not sent!")
send_tx.ok_button.click()
# TODO: disabled due to 10838 (rechecked 23.11.21, valid)
# transactions_view = wallet.transaction_history_button.click()
# transactions_view.transactions_table.find_transaction(amount=amount, asset=symbol)
self.errors.verify_no_errors()
@marks.testrail_id(700757)
def test_send_tx_set_recipient_options(self):
nickname = 'my_some_nickname'
account_name = 'my_acc_name'
account_address = '0x8c2E3Cd844848E79cFd4671cE45C12F210b630d7'
recent_add_to_fav_name = 'my_Recent_STT'
recent_add_to_fav_address = '0x58d8c3d70ce4fa4b9fb10a665c8712238746f2ff'
ens_status, ens_other = ens_user_ropsten, ens_user
basic_add_to_fav_name = 'my_basic_address'
self.drivers[0].reset()
self.home = self.sign_in.recover_access(wallet_users['D']['passphrase'])
self.home.just_fyi('Add new account and new ENS contact for recipient')
chat = self.home.add_contact(ens_status['ens'])
chat.chat_options.click()
chat.view_profile_button.click_until_presence_of_element(chat.remove_from_contacts)
chat.set_nickname(nickname)
wallet = self.home.wallet_button.click()
wallet.add_account(account_name=account_name)
wallet.accounts_status_account.click()
send_tr = wallet.send_transaction_button.click()
wallet.just_fyi("Check that can't send to invalid address")
send_tr.amount_edit_box.click()
send_tr.amount_edit_box.set_value(send_tr.get_unique_amount())
send_tr.chose_recipient_button.click()
for address in (basic_user['public_key'], '0xDE709F2102306220921060314715629080E2fB77'):
send_tr.enter_recipient_address_input.set_value(address)
send_tr.enter_recipient_address_input.click()
send_tr.done_button.click()
if send_tr.set_max_button.is_element_displayed():
self.errors.append('Can proceed with wrong address %s in recipient' % address)
send_tr.just_fyi('Set one of my accounts')
send_tr.chose_recipient_button.click_if_shown()
send_tr.element_by_translation_id("my-accounts").click()
send_tr.element_by_text(account_name).click()
if send_tr.enter_recipient_address_text.text != send_tr.get_formatted_recipient_address(account_address):
self.errors.append('Added account is not resolved as recipient')
send_tr.just_fyi('Set contract address from recent and check smart contract error')
send_tr.chose_recipient_button.click()
send_tr.element_by_translation_id("recent").click()
send_tr.element_by_text('↓ 1000 MDS').click()
if not send_tr.element_by_translation_id("warning-sending-to-contract-descr").is_element_displayed():
self.driver.fail('No warning is shown at attempt to set as recipient smart contract')
send_tr.ok_button.click()
send_tr.element_by_text('↑ 0.001 ETHro').scroll_and_click()
send_tr.add_to_favorites(recent_add_to_fav_name)
wallet.element_by_translation_id("recent").click()
send_tr.just_fyi('Scan invalid QR')
send_tr.scan_qr_code_button.click()
send_tr.allow_button.click(1)
wallet.enter_qr_edit_box.scan_qr('something%s' % basic_user['address'])
if not send_tr.element_by_text_part('Invalid address').is_element_displayed(10):
self.driver.fail('No error is shown at attempt to scan invalid address')
wallet.ok_button.click()
send_tr.just_fyi('Scan code, add it to favorites and recheck that it is preserved')
send_tr.scan_qr_code_button.click()
wallet.enter_qr_edit_box.scan_qr(basic_user['address'])
send_tr.add_to_favorites(basic_add_to_fav_name)
send_tr.element_by_translation_id("favourites").scroll_and_click()
for name in (recent_add_to_fav_name, basic_add_to_fav_name):
wallet.element_by_text(name).scroll_to_element()
send_tr.element_by_text(recent_add_to_fav_name).scroll_and_click()
if str(send_tr.enter_recipient_address_text.text).lower() != send_tr.get_formatted_recipient_address(
recent_add_to_fav_address):
self.errors.append('Recent address that was added to favourites was not resolved correctly')
send_tr.just_fyi('Set contact')
send_tr.chose_recipient_button.click()
send_tr.element_by_translation_id("contacts").scroll_and_click()
send_tr.element_by_text(nickname).scroll_and_click()
send_tr.recipient_done.click()
if send_tr.enter_recipient_address_text.text != send_tr.get_formatted_recipient_address(ens_status['address']):
self.errors.append('ENS from contact is not resolved as recipient')
send_tr.just_fyi('Set different ENS options')
send_tr.set_recipient_address(ens_other['ens_another'])
if send_tr.enter_recipient_address_text.text != send_tr.get_formatted_recipient_address(ens_other['address']):
self.errors.append('ENS address on another domain is not resolved as recipient')
send_tr.set_recipient_address('%s.stateofus.eth' % ens_status['ens'])
if send_tr.enter_recipient_address_text.text != send_tr.get_formatted_recipient_address(ens_status['address']):
self.errors.append('ENS address on stateofus.eth is not resolved as recipient')
send_tr.just_fyi('Check search and set address from search')
send_tr.chose_recipient_button.click()
send_tr.search_by_keyword(ens_status['ens'][:2])
if not send_tr.element_by_text('@' + ens_status['ens']).is_element_displayed():
self.errors.append('ENS address from contacts is not shown in search')
send_tr.cancel_button.click()
send_tr.search_by_keyword('my')
for name in (nickname, account_name, recent_add_to_fav_name, basic_add_to_fav_name):
if not send_tr.element_by_text(name).is_element_displayed():
self.errors.append('%s is not shown in search when searching by namepart' % name)
send_tr.element_by_text(basic_add_to_fav_name).click()
if send_tr.enter_recipient_address_text.text != send_tr.get_formatted_recipient_address(
'0x' + basic_user['address']):
self.errors.append('QR scanned address that was added to favourites was not resolved correctly')
self.errors.verify_no_errors()
class TestTransactionWalletSingleDevice(SingleDeviceTestCase):
@marks.testrail_id(5784)
@marks.medium
@marks.transaction
def test_sign_typed_message_deploy_simple_contract_request_pub_key_from_dapp(self):
user = transaction_senders['ETH_5']
home = SignInView(self.driver).recover_access(passphrase=user['passphrase'])
home.just_fyi("Checking requesting public key from dapp")
status_test_dapp = home.open_status_test_dapp(allow_all=False)
status_test_dapp.status_api_button.click_until_presence_of_element(status_test_dapp.request_contact_code_button)
status_test_dapp.request_contact_code_button.click_until_presence_of_element(status_test_dapp.deny_button)
status_test_dapp.deny_button.click()
if status_test_dapp.element_by_text(user['public_key']).is_element_displayed():
self.errors.append('Public key is returned but access was not allowed')
status_test_dapp.request_contact_code_button.click_until_presence_of_element(status_test_dapp.deny_button)
status_test_dapp.allow_button.click()
if not status_test_dapp.element_by_text(user['public_key']).is_element_displayed():
self.errors.append('Public key is not returned')
status_test_dapp.get_empty_dapp_tab()
home.wallet_button.click()
home.just_fyi("Checking sign typed message")
home.open_status_test_dapp(allow_all=True)
status_test_dapp.transactions_button.click_until_presence_of_element(status_test_dapp.sign_typed_message_button)
send_transaction = status_test_dapp.sign_typed_message_button.click()
send_transaction.enter_password_input.send_keys(common_password)
send_transaction.sign_button.click_until_absense_of_element(send_transaction.sign_button)
if not status_test_dapp.element_by_text_part('0x1673d96e836').is_element_displayed(30):
self.errors.append("Hash of signed typed message is not shown!")
home.just_fyi("Checking deploy simple contract")
send_transaction = status_test_dapp.deploy_contract_button.click()
send_transaction.sign_transaction()
if not status_test_dapp.element_by_text('Contract deployed at: ').is_element_displayed(240):
self.errors.append('Contract was not created')
for text in ['Call contract get function',
'Call contract set function', 'Call function 2 times in a row']:
status_test_dapp.element_by_text(text).scroll_to_element()
self.errors.verify_no_errors()
@marks.testrail_id(5429)
@marks.medium
def test_set_currency(self):
home = SignInView(self.driver).create_user()
user_currency = 'Euro (EUR)'
wallet = home.wallet_button.click()
wallet.set_currency(user_currency)
if not wallet.element_by_text_part('EUR').is_element_displayed(20):
self.driver.fail('EUR currency is not displayed')
@marks.testrail_id(5358)
@marks.medium
def test_backup_recovery_phrase_warning_from_wallet(self):
sign_in = SignInView(self.driver)
sign_in.create_user()
wallet = sign_in.wallet_button.click()
if wallet.backup_recovery_phrase_warning_text.is_element_present():
self.driver.fail("'Back up your seed phrase' warning is shown on Wallet while no funds are present")
address = wallet.get_wallet_address()
self.network_api.get_donate(address[2:], external_faucet=True, wait_time=200)
wallet.close_button.click()
wallet.wait_balance_is_changed(scan_tokens=True)
if not wallet.backup_recovery_phrase_warning_text.is_element_present(30):
self.driver.fail("'Back up your seed phrase' warning is not shown on Wallet with funds")
profile = wallet.get_profile_view()
wallet.backup_recovery_phrase_warning_text.click()
profile.backup_recovery_phrase()
@marks.testrail_id(5407)
@marks.medium
@marks.transaction
def test_offline_can_login_cant_send_transaction(self):
home = SignInView(self.driver).create_user()
wallet = home.wallet_button.click()
wallet.toggle_airplane_mode()
wallet.accounts_status_account.click_until_presence_of_element(wallet.send_transaction_button)
send_transaction = wallet.send_transaction_button.click()
send_transaction.set_recipient_address('0x%s' % basic_user['address'])
send_transaction.amount_edit_box.set_value("0")
send_transaction.confirm()
send_transaction.sign_transaction_button.click()
if send_transaction.sign_with_password.is_element_displayed():
self.driver.fail("Sign transaction button is active in offline mode")
self.driver.close_app()
self.driver.launch_app()
SignInView(self.driver).sign_in()
home.home_button.wait_for_visibility_of_element()
home.connection_offline_icon.wait_for_visibility_of_element(20)
@marks.testrail_id(6225)
@marks.transaction
@marks.medium
def test_send_funds_between_accounts_in_multiaccount_instance(self):
sign_in = SignInView(self.driver)
sign_in.create_user()
wallet = sign_in.wallet_button.click()
status_account_address = wallet.get_wallet_address()[2:]
self.network_api.get_donate(status_account_address, external_faucet=True)
wallet.wait_balance_is_changed()
account_name = 'subaccount'
wallet.add_account(account_name)
wallet.just_fyi("Send transaction to new account")
initial_balance = self.network_api.get_balance(status_account_address)
transaction_amount = '0.003%s' % str(random.randint(10000, 99999)) + '1'
wallet.send_transaction(account_name=account_name, amount=transaction_amount)
self.network_api.wait_for_confirmation_of_transaction(status_account_address, transaction_amount)
self.network_api.verify_balance_is_updated(str(initial_balance), status_account_address)
wallet.just_fyi("Verifying previously sent transaction in new account")
wallet.get_account_by_name(account_name).click()
wallet.send_transaction_button.click()
wallet.close_send_transaction_view_button.click()
balance_after_receiving_tx = float(wallet.get_asset_amount_by_name('ETH'))
expected_balance = self.network_api.get_rounded_balance(balance_after_receiving_tx, transaction_amount)
if balance_after_receiving_tx != expected_balance:
self.driver.fail('New account balance %s does not match expected %s after receiving a transaction' % (
balance_after_receiving_tx, transaction_amount))
wallet.just_fyi("Sending eth from new account to main account")
updated_balance = self.network_api.get_balance(status_account_address)
transaction_amount_1 = round(float(transaction_amount) * 0.2, 12)
wallet.send_transaction(from_main_wallet=False, account_name=wallet.status_account_name,
amount=transaction_amount_1)
wallet.close_button.click()
sub_account_address = wallet.get_wallet_address(account_name)[2:]
self.network_api.wait_for_confirmation_of_transaction(status_account_address, transaction_amount_1)
self.network_api.verify_balance_is_updated(updated_balance, status_account_address)
wallet.find_transaction_in_history(amount=transaction_amount)
wallet.find_transaction_in_history(amount=format(float(transaction_amount_1), '.11f').rstrip('0'))
wallet.just_fyi("Check transactions on subaccount")
self.network_api.verify_balance_is_updated(updated_balance, status_account_address)
wallet.just_fyi("Verify total ETH on main wallet view")
self.network_api.wait_for_confirmation_of_transaction(status_account_address, transaction_amount_1)
self.network_api.verify_balance_is_updated((updated_balance + transaction_amount_1), status_account_address)
wallet.close_button.click()
balance_of_sub_account = float(self.network_api.get_balance(sub_account_address)) / 1000000000000000000
balance_of_status_account = float(self.network_api.get_balance(status_account_address)) / 1000000000000000000
wallet.scan_tokens()
total_eth_from_two_accounts = float(wallet.get_asset_amount_by_name('ETH'))
expected_balance = self.network_api.get_rounded_balance(total_eth_from_two_accounts,
(balance_of_status_account + balance_of_sub_account))
if total_eth_from_two_accounts != expected_balance:
self.driver.fail('Total wallet balance %s != of Status account (%s) + SubAccount (%s)' % (
total_eth_from_two_accounts, balance_of_status_account, balance_of_sub_account))
@marks.testrail_id(6235)
@marks.medium
def test_can_change_account_settings(self):
sign_in_view = SignInView(self.driver)
sign_in_view.create_user()
wallet_view = sign_in_view.wallet_button.click()
status_account_address = wallet_view.get_wallet_address()
wallet_view.get_account_options_by_name().click()
wallet_view.just_fyi('open Account Settings screen and check that all elements are shown')
wallet_view.account_settings_button.click()
for text in 'On Status tree', status_account_address, "m/44'/60'/0'/0/0":
if not wallet_view.element_by_text(text).is_element_displayed():
self.errors.append("'%s' text is not shown on Account Settings screen!" % text)
wallet_view.just_fyi('change account name/color and verified applied changes')
account_name = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(10))
wallet_view.account_name_input.clear()
wallet_view.account_name_input.send_keys(account_name)
wallet_view.account_color_button.select_color_by_position(1)
wallet_view.apply_settings_button.click()
wallet_view.element_by_text('This device').scroll_to_element()
wallet_view.close_button.click()
wallet_view.close_button.click()
account_button = wallet_view.get_account_by_name(account_name)
if not account_button.is_element_displayed():
self.driver.fail('Account name was not changed')
if not account_button.color_matches('multi_account_color.png'):
self.driver.fail('Account color does not match expected')
self.errors.verify_no_errors()
@marks.testrail_id(6282)
@marks.medium
def test_can_scan_eip_681_links(self):
sign_in = SignInView(self.driver)
sign_in.recover_access(transaction_senders['C']['passphrase'])
wallet = sign_in.wallet_button.click()
wallet.wait_balance_is_changed()
send_transaction_view = SendTransactionView(self.driver)
sign_in.just_fyi("Setting up wallet")
wallet.accounts_status_account.click_until_presence_of_element(wallet.send_transaction_button)
send_transaction = wallet.send_transaction_button.click()
send_transaction.set_recipient_address('0x%s' % basic_user['address'])
send_transaction.amount_edit_box.set_value("0")
send_transaction.confirm()
send_transaction.sign_transaction_button.click()
wallet.set_up_wallet_when_sending_tx()
wallet.cancel_button.click()
wallet.close_button.click()
url_data = {
'ens_for_receiver': {
'url': 'ethereum:0xc55cf4b03948d7ebc8b9e8bad92643703811d162@3/transfer?address=nastya.stateofus.eth&uint256=1e-1',
'data': {
'asset': 'STT',
'amount': '0.1',
'address': '0x58d8…F2ff',
},
},
# 'gas_settings': {
# 'url': 'ethereum:0x3d597789ea16054a084ac84ce87f50df9198f415@3?value=1e16&gasPrice=1000000000&gasLimit=100000',
# 'data': {
# 'amount': '0.01',
# 'asset': 'ETHro',
# 'address': '0x3D59…F415',
# 'gas_limit': '100000',
# 'gas_price': '1',
# },
# },
'payment_link': {
'url': 'ethereum:pay-0xc55cf4b03948d7ebc8b9e8bad92643703811d162@3/transfer?address=0x3d597789ea16054a084ac84ce87f50df9198f415&uint256=1e1',
'data': {
'amount': '10',
'asset': 'STT',
'address': '0x3D59…F415',
},
},
'validation_amount_too_presize': {
'url': 'ethereum:0xc55cf4b03948d7ebc8b9e8bad92643703811d162@3/transfer?address=0x101848D5C5bBca18E6b4431eEdF6B95E9ADF82FA&uint256=1e-19',
'data': {
'amount': '1e-19',
'asset': 'STT',
'address': '0x1018…82FA',
},
'send_transaction_validation_error': 'Amount is too precise',
},
'validation_amount_too_big': {
'url': 'ethereum:0x101848D5C5bBca18E6b4431eEdF6B95E9ADF82FA@3?value=1e25',
'data': {
'amount': '10000000',
'asset': 'ETHro',
'address': '0x1018…82FA',
},
'send_transaction_validation_error': 'Insufficient funds',
},
'validation_wrong_chain_id': {
'url': 'ethereum:0x101848D5C5bBca18E6b4431eEdF6B95E9ADF82FA?value=1e17',
'error': 'Network does not match',
'data': {
'amount': '0.1',
'asset': 'ETHro',
'address': '0x1018…82FA',
},
},
'validation_wrong_address': {
'url': 'ethereum:0x744d70fdbe2ba4cf95131626614a1763df805b9e@3/transfer?address=blablabla&uint256=1e10',
'error': 'Invalid address',
},
}
for key in url_data:
wallet.just_fyi('Checking %s case' % key)
wallet.scan_qr_button.click()
if wallet.allow_button.is_element_displayed():
wallet.allow_button.click()
wallet.enter_qr_edit_box.scan_qr(url_data[key]['url'])
if url_data[key].get('error'):
if not wallet.element_by_text_part(url_data[key]['error']).is_element_displayed():
self.errors.append('Expected error %s is not shown' % url_data[key]['error'])
wallet.ok_button.click()
if url_data[key].get('data'):
actual_data = send_transaction_view.get_values_from_send_transaction_bottom_sheet()
difference_in_data = url_data[key]['data'].items() - actual_data.items()
if difference_in_data:
self.errors.append(
'In %s case returned value does not match expected in %s' % (key, repr(difference_in_data)))
if url_data[key].get('send_transaction_validation_error'):
error = url_data[key]['send_transaction_validation_error']
if not wallet.element_by_text_part(error).is_element_displayed():
self.errors.append(
'Expected error %s is not shown' % error)
if wallet.close_send_transaction_view_button.is_element_displayed():
wallet.close_send_transaction_view_button.wait_and_click()
else:
wallet.cancel_button.wait_and_click()
self.errors.verify_no_errors()
@marks.testrail_id(5437)
@marks.medium
def test_validation_amount_errors(self):
sender = wallet_users['C']
sign_in = SignInView(self.driver)
errors = {'send_transaction_screen': {
'too_precise': 'Amount is too precise. Max number of decimals is 7.',
'insufficient_funds': 'Insufficient funds'
},
'sending_screen': {
'Amount': 'Insufficient funds',
'Network fee': 'Not enough ETH for gas'
},
}
warning = 'Warning %s is not shown on %s'
sign_in.recover_access(sender['passphrase'])
wallet = sign_in.wallet_button.click()
wallet.wait_balance_is_changed('ADI')
wallet.accounts_status_account.click()
screen = 'send transaction screen from wallet'
sign_in.just_fyi('Checking %s on %s' % (errors['send_transaction_screen']['too_precise'], screen))
initial_amount_adi = wallet.get_asset_amount_by_name('ADI')
send_transaction = wallet.send_transaction_button.click()
adi_button = send_transaction.asset_by_name('ADI')
send_transaction.select_asset_button.click_until_presence_of_element(
send_transaction.eth_asset_in_select_asset_bottom_sheet_button)
adi_button.click()
send_transaction.amount_edit_box.click()
amount = '0.000%s' % str(random.randint(100000, 999999)) + '1'
send_transaction.amount_edit_box.set_value(amount)
if not send_transaction.element_by_text(
errors['send_transaction_screen']['too_precise']).is_element_displayed():
self.errors.append(warning % (errors['send_transaction_screen']['too_precise'], screen))
sign_in.just_fyi('Checking %s on %s' % (errors['send_transaction_screen']['insufficient_funds'], screen))
send_transaction.amount_edit_box.clear()
send_transaction.amount_edit_box.set_value(str(initial_amount_adi) + '1')
if not send_transaction.element_by_text(
errors['send_transaction_screen']['insufficient_funds']).is_element_displayed():
self.errors.append(warning % (errors['send_transaction_screen']['insufficient_funds'], screen))
wallet.close_send_transaction_view_button.click()
wallet.close_button.click()
screen = 'sending screen from wallet'
sign_in.just_fyi('Checking %s on %s' % (errors['sending_screen']['Network fee'], screen))
account_name = 'new'
wallet.add_account(account_name)
wallet.get_account_by_name(account_name).click()
wallet.send_transaction_button.click()
send_transaction.amount_edit_box.set_value('0')
send_transaction.set_recipient_address(ens_user_ropsten['ens'])
send_transaction.next_button.click()
wallet.ok_got_it_button.wait_and_click(30)
if not send_transaction.validation_error_element.is_element_displayed(10):
self.errors.append('Validation icon is not shown when testing %s on %s' % (errors['sending_screen']['Network fee'], screen))
if not wallet.element_by_translation_id("tx-fail-description2").is_element_displayed():
self.errors.append("No warning about failing tx is shown!")
send_transaction.cancel_button.click()
screen = 'sending screen from DApp'
sign_in.just_fyi('Checking %s on %s' % (errors['sending_screen']['Network fee'], screen))
home = wallet.home_button.click()
dapp = sign_in.dapp_tab_button.click()
dapp.select_account_button.click()
dapp.select_account_by_name(account_name).wait_for_element(30)
dapp.select_account_by_name(account_name).click()
status_test_dapp = home.open_status_test_dapp()
status_test_dapp.wait_for_d_aap_to_load()
status_test_dapp.transactions_button.click_until_presence_of_element(
status_test_dapp.send_two_tx_in_batch_button)
status_test_dapp.send_two_tx_in_batch_button.click()
if not send_transaction.validation_error_element.is_element_displayed(10):
self.errors.append(warning % (errors['sending_screen']['Network fee'], screen))
self.errors.verify_no_errors()
@marks.testrail_id(695855)
@marks.transaction
@marks.medium
def test_custom_gas_settings(self):
sender = transaction_senders['ETH_7']
sign_in = SignInView(self.driver)
sign_in.recover_access(sender['passphrase'])
wallet = sign_in.wallet_button.click()
wallet.wait_balance_is_changed()
wallet.accounts_status_account.click()
send_transaction = wallet.send_transaction_button.click()
amount = '0.000%s' % str(random.randint(100000, 999999)) + '1'
send_transaction.amount_edit_box.set_value(amount)
send_transaction.set_recipient_address(ens_user_ropsten['ens'])
send_transaction.next_button.click()
wallet.ok_got_it_button.wait_and_click(30)
send_transaction.network_fee_button.click()
send_transaction = wallet.get_send_transaction_view()
fee_fields = (send_transaction.per_gas_tip_limit_input, send_transaction.per_gas_price_limit_input)
[default_tip, default_price] = [field.text for field in fee_fields]
default_limit = '21000'
wallet.just_fyi("Check basic validation")
values = {
send_transaction.gas_limit_input:
{
'default': default_limit,
'value': '22000',
'20999': 'wallet-send-min-units',
'@!': 'invalid-number',
},
send_transaction.per_gas_tip_limit_input:
{
'default': default_tip,
'value': '2.5',
'aaaa': 'invalid-number',
},
send_transaction.per_gas_price_limit_input:
{
'default': default_price,
'value': str(round(float(default_price)+3, 9)),
'-2': 'invalid-number',
}
}
for field in values:
for key in values[field]:
if key != 'default' and key != 'value':
field.clear()
field.send_keys(key)
if not send_transaction.element_by_translation_id(values[field][key]).is_element_displayed(10):
self.errors.append("%s is not shown for %s" % (values[field][key], field.accessibility_id))
field.clear()
field.set_value(values[field]['value'])
wallet.just_fyi("Set custom fee and check that it will be applied")
send_transaction.save_fee_button.scroll_and_click()
if wallet.element_by_translation_id("change-tip").is_element_displayed():
wallet.element_by_translation_id("continue-anyway").click()
send_transaction.sign_transaction()
self.network_api.wait_for_confirmation_of_transaction(sender['address'], amount, confirmations=3)
transaction = wallet.find_transaction_in_history(amount=amount, return_hash=True)
expected_params = {
'fee_cap': values[send_transaction.per_gas_price_limit_input]['value'],
'tip_cap': '2.5',
'gas_limit': '22000'
}
actual_params = self.network_api.get_custom_fee_tx_params(transaction)
if actual_params != expected_params:
self.errors.append('Real params %s for tx do not match expected %s' % (str(actual_params), str(expected_params)))
wallet.just_fyi('Verify custom fee data on tx screen')
wallet.swipe_up()
for key in expected_params:
if not wallet.element_by_text_part(expected_params[key]).is_element_displayed():
self.errors.append("Custom tx param %s is not shown on tx history screen" % key)
wallet.just_fyi("Check below fee popup on mainnet")
profile = wallet.profile_button.click()
profile.switch_network()
sign_in.wallet_button.click()
wallet.accounts_status_account.click()
send_transaction = wallet.send_transaction_button.click_until_presence_of_element(send_transaction.amount_edit_box)
send_transaction.amount_edit_box.set_value(0)
send_transaction.set_recipient_address(ens_user_ropsten['ens'])
send_transaction.next_button.click()
wallet.element_by_translation_id("network-fee").click()
if not wallet.element_by_translation_id("tx-fail-description2").is_element_displayed():
self.errors.append("Tx is likely to fail is not shown!")
if send_transaction.network_fee_button.is_element_displayed():
self.errors.append("Still can set tx fee when balance is not enough")
## TODO: should be moved to another test after 8f52b9b63ccd9a52b7fe37ab4f89a2e7b6721fcd
# send_transaction = wallet.get_send_transaction_view()
# send_transaction.gas_limit_input.clear()
# send_transaction.gas_limit_input.set_value(default_limit)
# send_transaction.per_gas_price_limit_input.clear()
# send_transaction.per_gas_price_limit_input.click()
# send_transaction.per_gas_price_limit_input.send_keys('1')
# if not wallet.element_by_translation_id("below-base-fee").is_element_displayed(10):
# self.errors.append("Fee is below error is not shown")
# send_transaction.save_fee_button.scroll_and_click()
# if not wallet.element_by_translation_id("change-tip").is_element_displayed():
# self.errors.append("Popup about changing fee error is not shown")
# wallet.element_by_translation_id("continue-anyway").click()
# if not send_transaction.element_by_text_part('0.000021 ETH').is_element_displayed():
# self.driver.fail("Custom fee is not applied!")
self.errors.verify_no_errors()
class TestTransactionWalletMultipleDevice(MultipleDeviceTestCase):
@marks.testrail_id(6330)
@marks.medium
@marks.transaction
def test_can_send_all_tokens_via_max_option(self):
sender = transaction_senders['ETH_STT_2']
receiver = transaction_senders['ETH_1']
self.create_drivers(2)
device_1, device_2 = SignInView(self.drivers[0]), SignInView(self.drivers[1])
home_1, home_2 = device_1.recover_access(sender['passphrase']), device_2.recover_access(receiver['passphrase'])
wallet_sender = home_1.wallet_button.click()
wallet_receiver = home_2.wallet_button.click()
if wallet_receiver.asset_by_name('STT').is_element_present(10):
initial_balance = wallet_receiver.get_asset_amount_by_name("STT")
else:
initial_balance = '0'
device_1.just_fyi("Sending token amount to device who will use Set Max option for token")
amount = '0.012345678912345678'
wallet_sender.send_transaction(asset_name='STT', amount=amount, recipient=receiver['address'])
wallet_receiver.wait_balance_is_changed(asset='STT', initial_balance=initial_balance, scan_tokens=True)
wallet_receiver.accounts_status_account.click()
device_1.just_fyi("Send all tokens via Set Max option")
send_transaction = wallet_receiver.send_transaction_button.click()
send_transaction.select_asset_button.click()
asset_name = 'STT'
asset_button = send_transaction.asset_by_name(asset_name)
send_transaction.select_asset_button.click_until_presence_of_element(
send_transaction.eth_asset_in_select_asset_bottom_sheet_button)
asset_button.click()
send_transaction.set_max_button.click()
send_transaction.set_recipient_address(sender['address'])
send_transaction.sign_transaction_button.click()
send_transaction.sign_transaction()
wallet_receiver.close_button.click()
initial_balance = float(initial_balance) + float(amount)
wallet_receiver.wait_balance_is_changed(asset='STT', initial_balance=str(initial_balance), scan_tokens=True)
@@ -0,0 +1,563 @@
import pytest
from tests import marks
from tests.base_test_case import MultipleDeviceTestCase, MultipleSharedDeviceTestCase, create_shared_drivers
from tests.users import transaction_senders, basic_user, ens_user, ens_user_ropsten
from views.sign_in_view import SignInView
from views.chat_view import ChatView
# TODO: moved here until resolve of 13048
@pytest.mark.xdist_group(name="group_chat_3")
@marks.critical
class TestPublicChatMultipleDeviceMerged(MultipleSharedDeviceTestCase):
@classmethod
def setup_class(cls):
cls.drivers, cls.loop = create_shared_drivers(3)
cls.message_before_adding = 'message before adding new user'
cls.message_to_admin = 'Hey, admin!'
cls.homes, cls.public_keys, cls.usernames, cls.chats = {}, {}, {}, {}
for key in cls.drivers:
sign_in = SignInView(cls.drivers[key])
cls.homes[key] = sign_in.create_user(enable_notifications=True)
cls.public_keys[key], cls.usernames[key] = sign_in.get_public_key_and_username(True)
sign_in.home_button.click()
cls.chat_name = cls.homes[0].get_random_chat_name()
cls.homes[0].just_fyi('Admin adds future members to contacts')
for i in range(1, 3):
cls.homes[0].add_contact(cls.public_keys[i])
cls.homes[0].home_button.double_click()
cls.homes[0].just_fyi('Member adds admin to contacts to see PNs and put app in background')
cls.homes[1].add_contact(cls.public_keys[0])
cls.homes[1].home_button.double_click()
cls.homes[0].just_fyi('Admin creates group chat')
cls.chats[0] = cls.homes[0].create_group_chat([cls.usernames[1]], cls.chat_name)
for i in range(1, 3):
cls.chats[i] = ChatView(cls.drivers[i])
cls.chats[0].send_message(cls.message_before_adding)
@marks.testrail_id(3994)
def test_group_chat_push_system_messages_when_invited(self):
self.homes[1].just_fyi("Check system messages in PNs")
self.homes[1].put_app_to_background()
self.homes[1].open_notification_bar()
pns = [self.chats[0].pn_invited_to_group_chat(self.usernames[0], self.chat_name),
self.chats[0].pn_wants_you_to_join_to_group_chat(self.usernames[0], self.chat_name)]
for pn in pns:
if not self.homes[1].get_pn(pn):
self.errors.append('%s is not shown after invite to group chat' % pn)
if self.homes[1].get_pn(pns[0]):
group_invite_pn = self.homes[1].get_pn(pns[0])
group_invite_pn.click()
else:
self.homes[1].click_system_back_button(2)
self.homes[1].get_chat(self.chat_name).click()
self.homes[1].just_fyi("Check system messages in group chat for admin and member")
create_system_message = self.chats[0].create_system_message(self.usernames[0], self.chat_name)
invite_system_message = self.chats[0].invite_system_message(self.usernames[0], self.usernames[1])
invited_to_join = self.chats[0].invited_to_join_system_message(self.usernames[0], self.chat_name)
create_for_admin_system_message = self.chats[0].create_for_admin_system_message(self.chat_name)
for message in [create_for_admin_system_message, create_system_message, invite_system_message]:
if not self.chats[0].chat_element_by_text(message):
self.errors.append('%s system message is not shown' % message)
for message in [invited_to_join, create_system_message, invite_system_message]:
if not self.chats[1].chat_element_by_text(message):
self.errors.append('%s system message is not shown' % message)
self.errors.verify_no_errors()
@marks.testrail_id(700731)
def test_group_chat_join_send_text_messages_push(self):
message_to_admin = self.message_to_admin
[self.homes[i].home_button.double_click() for i in range(3)]
self.homes[1].get_chat(self.chat_name).click()
self.chats[1].just_fyi('Join to group chat')
join_system_message = self.chats[1].join_system_message(self.usernames[1])
self.chats[1].join_chat_button.click()
if not self.chats[1].chat_element_by_text(join_system_message).is_element_displayed(30):
self.drivers[1].fail('System message after joining group chat is not shown')
self.chats[1].send_message(message_to_admin)
self.chats[0].just_fyi('check that PN is received and after tap you are redirected to group chat')
self.chats[0].open_notification_bar()
pn = self.homes[0].get_pn(message_to_admin)
if pn:
pn.click()
else:
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')
message_status = self.chats[1].chat_element_by_text(message_to_admin).status
if message_status != 'delivered':
self.errors.append('Message status is not delivered, it is %s!' % message_status)
for message in (join_system_message, message_to_admin):
if not self.chats[0].chat_element_by_text(message).is_element_displayed(30):
self.drivers[0].fail('Message %s was not received by admin' % message)
self.errors.verify_no_errors()
@marks.testrail_id(700732)
def test_group_chat_add_new_member_activity_centre(self):
[self.homes[i].home_button.double_click() for i in range(3)]
self.homes[0].get_chat(self.chat_name).click()
self.chats[0].add_members_to_group_chat([self.usernames[2]])
self.chats[2].just_fyi("Check there will be no PN but unread in AC if got invite from non-contact")
if not self.homes[2].notifications_unread_badge.is_element_displayed(60):
self.drivers[2].fail("Group chat is not appeared in AC!")
self.homes[2].open_notification_bar()
if self.homes[2].element_by_text_part(self.usernames[0]).is_element_displayed():
self.errors.append("PN about group chat invite is shown when invited by non-contact")
self.homes[2].click_system_back_button()
self.homes[2].get_chat(self.chat_name).click()
self.chats[2].join_chat_button.click()
for message in (self.message_to_admin, self.message_before_adding):
if self.chats[2].chat_element_by_text(message).is_element_displayed():
self.errors.append('%s is shown for new user' % message)
self.errors.verify_no_errors()
@marks.testrail_id(3998)
def test_group_chat_offline_pn(self):
[self.homes[i].home_button.double_click() for i in range(3)]
chat_name = 'for_offline_pn'
self.homes[0].create_group_chat([self.usernames[1], self.usernames[2]], chat_name)
self.homes[0].home_button.double_click()
for i in range(1, 3):
self.homes[i].get_chat(chat_name).click()
self.chats[i].join_chat_button.click()
message_1, message_2 = 'message from old member', 'message from new member'
self.homes[0].just_fyi("Put admin device to offline and send messages from members")
self.homes[0].toggle_airplane_mode()
self.chats[1].send_message(message_1)
self.chats[2].send_message(message_2)
self.homes[0].just_fyi("Put admin device to online and check that messages and PNs will be fetched")
self.homes[0].toggle_airplane_mode()
self.homes[0].connection_offline_icon.wait_for_invisibility_of_element(60)
self.homes[0].open_notification_bar()
for message in (message_1, message_2):
if not self.homes[0].get_pn(message):
self.errors.append('%s PN was not fetched from offline' % message)
self.homes[0].click_system_back_button()
unread_group = self.homes[0].get_chat(chat_name)
if not unread_group.new_messages_counter.text == '2':
self.errors.append('%s does not match unread messages' % unread_group.new_messages_counter.text)
unread_group.click()
self.homes[0].just_fyi("check that messages are shown for every member")
for i in range(3):
for message in (message_1, message_2):
if not self.chats[i].chat_element_by_text(message).is_element_displayed():
self.errors.append('%s if not shown for device %s' % (message, str(i)))
self.errors.verify_no_errors()
@marks.testrail_id(5756)
def test_group_chat_decline_invite_chat_highligted(self):
chat_name = 'for_invited'
left_system_message = self.chats[0].leave_system_message(self.usernames[1])
[self.homes[i].home_button.double_click() for i in range(3)]
self.homes[0].create_group_chat([self.usernames[1]], chat_name)
self.homes[1].just_fyi("Check that new group chat from contact is highlited")
chat_2_element = self.homes[1].get_chat(chat_name)
if chat_2_element.no_message_preview.is_element_differs_from_template('highligted_preview_group.png', 0):
self.errors.append("Preview message is not hightligted or text is not shown! ")
chat_2 = self.homes[1].get_chat(chat_name).click()
chat_2.home_button.click()
if not chat_2_element.no_message_preview.is_element_differs_from_template('highligted_preview_group.png', 0):
self.errors.append("Preview message is still hightligted after opening! ")
self.homes[1].get_chat(chat_name).click()
chat_2.decline_invitation_button.click()
if self.chats[0].chat_element_by_text(left_system_message).is_element_displayed():
self.errors.append('System message when user declined invite is shown')
if self.homes[1].element_by_text(chat_name).is_element_displayed():
self.errors.append("Group chat '%s' is shown, but user declined invite" % chat_name)
self.homes[0].just_fyi('Send message after invite is declined and check that it is not reappeared')
message = 'sent after leaving'
self.chats[0].send_message(message)
if self.homes[1].element_by_text(chat_name).is_element_displayed():
self.errors.append("Group chat '%s' reappeared when new message is sent" % chat_name)
self.errors.verify_no_errors()
@marks.testrail_id(3997)
def test_group_chat_leave_relogin(self):
self.drivers[2].quit()
[self.homes[i].home_button.double_click() for i in range(2)]
self.homes[0].home_button.double_click()
self.homes[1].get_chat(self.chat_name).click()
join_button = self.chats[1].join_chat_button
if join_button.is_element_displayed():
join_button.click()
self.homes[0].just_fyi("Admin deleted chat via long press")
self.homes[0].leave_chat_long_press(self.chat_name)
self.homes[0].just_fyi("Member sends some message, admin relogins and check chat does not reappear")
self.chats[1].send_message(self.message_to_admin)
self.homes[0].relogin()
if self.homes[0].get_chat_from_home_view(self.chat_name).is_element_displayed():
self.drivers[0].fail('Deleted %s is present after relaunch app' % self.chat_name)
class TestGroupChatMultipleDevice(MultipleDeviceTestCase):
@marks.testrail_id(5762)
@marks.high
def test_pair_devices_sync_one_to_one_contacts_nicknames_public_chat(self):
self.create_drivers(3)
device_1, device_2, device_3 = SignInView(self.drivers[0]), SignInView(self.drivers[1]), SignInView(
self.drivers[2])
no_contact_nickname = 'no_contact_nickname'
name_1, name_2 = 'device_%s' % device_1.driver.number, 'device_%s' % device_2.driver.number
message_before_sync, message_after_sync = 'sent before sync', 'sent after sync'
message_blocked_before, message_blocked_after = 'I am blocked user', 'Not blocked anymore'
public_chat_before_sync, public_chat_after_sync = device_1.get_random_chat_name(), 'after-pairing'
device_3.just_fyi("Block contact: create user for blocking from main device")
home_3 = device_3.create_user()
public_chat_3 = home_3.join_public_chat(public_chat_before_sync)
public_chat_3.send_message(message_blocked_before)
self.drivers[2].quit()
device_1.just_fyi("(main device): create main user")
home_1 = device_1.create_user()
profile_1 = home_1.profile_button.click()
profile_1.privacy_and_security_button.click()
profile_1.backup_recovery_phrase_button.click()
profile_1.ok_continue_button.click()
recovery_phrase = profile_1.get_recovery_phrase()
profile_1.close_button.click()
profile_1.home_button.click()
profile_1.get_recovery_phrase()
device_1.just_fyi('Add contact, 1-1 chat (main device): 3-random, contact with ENS, start 1-1')
chat_1 = home_1.add_contact(basic_user['public_key'])
chat_1.send_message(message_before_sync)
chat_1.home_button.click()
chat_1 = home_1.add_contact(ens_user['ens'])
chat_1.home_button.click()
device_1.just_fyi('Chats, contacts (main device): join public chat, block user, set nickname')
public_chat_1 = home_1.join_public_chat(public_chat_before_sync)
public_chat_1.open_user_profile_from_public_chat(message_blocked_before)
public_chat_1.set_nickname(no_contact_nickname, close_profile=False)
public_chat_1.block_contact()
device_2.just_fyi("(secondary device): restore same multiaccount on another device")
home_2 = device_2.recover_access(passphrase=' '.join(recovery_phrase.values()))
profile_1, profile_2 = home_1.profile_button.click(), home_2.profile_button.click()
device_2.just_fyi('Nicknames (main device): set nickname for contact')
profile_1.open_contact_from_profile(basic_user['username'])
nickname = 'my_basic_user'
chat_1.set_nickname(nickname)
device_1.back_button.click()
device_2.just_fyi('Pair main and secondary devices')
profile_2.discover_and_advertise_device(name_2)
profile_1.discover_and_advertise_device(name_1)
profile_1.get_toggle_device_by_name(name_2).wait_and_click()
profile_1.sync_all_button.click()
profile_1.sync_all_button.wait_for_visibility_of_element(20)
[device.profile_button.click() for device in (profile_1, profile_2)]
device_2.just_fyi('Contacts (secondary device): check contacts + blocked users after initial sync')
profile_2.contacts_button.scroll_to_element(9, 'up')
profile_2.contacts_button.click()
if not profile_2.blocked_users_button.is_element_displayed(30):
self.errors.append('Blocked users are not synced after initial sync')
for name in (basic_user['username'], nickname, '@%s' % ens_user['ens']):
if not profile_2.element_by_text(name).is_element_displayed():
self.errors.append('"%s" is not found in Contacts after initial sync' % name)
profile_2.blocked_users_button.click()
if not profile_2.element_by_text(no_contact_nickname).is_element_displayed():
self.errors.append(
"'%s' nickname without addeing to contacts is not synced after initial sync" % no_contact_nickname)
profile_2.profile_button.double_click()
device_1.just_fyi("Contacts(main device): unblock user, send message from unblocked user")
profile_1.profile_button.click()
profile_1.contacts_button.scroll_to_element(direction='up')
profile_1.contacts_button.click()
profile_1.blocked_users_button.click()
profile_1.element_by_text(no_contact_nickname).click()
public_chat_1.unblock_contact_button.click()
profile_1.close_button.click()
device_1.just_fyi('Chats, contacts, nickname (main device): send message to 1-1, add new contact')
profile_1.home_button.click(desired_view='chat')
public_chat_1.back_button.click()
home_1.get_chat(nickname).click()
chat_1.send_message(message_after_sync)
chat_1.back_button.click()
new_contact, new_contact_ens = transaction_senders['A'], ens_user_ropsten
home_1.add_contact(new_contact['public_key'])
home_1.home_button.click()
home_1.add_contact(new_contact_ens['ens'])
device_2.just_fyi('Contacts (secondary device): check unblocked user, new contact')
profile_2.contacts_button.click()
profile_2.blocked_users_button.wait_for_invisibility_of_element(60)
for name in (new_contact['username'], '@%s' % new_contact_ens['ens']):
if not profile_2.element_by_text(name).is_element_displayed(60):
self.errors.append('"%s" is not found in Contacts after adding when devices are paired' % name)
device_1.just_fyi('Contacts (main device): set nickname, (secondary device): check that synced')
home_1.profile_button.click()
profile_1.contacts_button.scroll_to_element(9, 'up')
profile_1.open_contact_from_profile(transaction_senders['A']['username'])
nickname_after_sync = 'my_transaction sender'
chat_1.set_nickname(nickname_after_sync)
device_1.home_button.double_click()
if not profile_2.element_by_text(nickname_after_sync).is_element_displayed(60):
self.errors.append(
'"%s" is not updated in Contacts after setting nickname when devices are paired' % nickname_after_sync)
device_2.just_fyi("Chats(secondary device): check public chats")
profile_2.home_button.click()
if not home_2.element_by_text_part(public_chat_before_sync).is_element_displayed():
self.errors.append(
'"%s" is not found in Home after initial sync when devices are paired' % public_chat_before_sync)
public_chat_2 = home_2.get_chat('#%s' % public_chat_before_sync).click()
if public_chat_2.chat_element_by_text(message_blocked_before).is_element_displayed(30):
self.errors.append('Message %s from previously blocked user is fetched' % message_blocked_before)
home_2.just_fyi("Chats (secondary device): check messages in 1-1")
public_chat_2.home_button.click()
chat = home_2.get_chat(nickname).click()
if chat.chat_element_by_text(message_before_sync).is_element_displayed():
self.errors.append('"%s" message sent before pairing is synced' % message_before_sync)
if not chat.chat_element_by_text(message_after_sync).is_element_displayed(60):
self.errors.append('"%s" message in 1-1 is not synced' % message_after_sync)
device_1.just_fyi('Chats (main device):add new public chat, (secondary device): check that synced')
home_1.join_public_chat(public_chat_after_sync)
home_2 = chat.get_back_to_home_view()
if not home_2.element_by_text_part(public_chat_after_sync).is_element_displayed(20):
self.errors.append(
'"%s" public chat is not synced after adding when devices are paired' % public_chat_after_sync)
home_1.just_fyi('Contacts (main device): remove and block contact')
home_1.profile_button.click()
profile_1.contacts_button.scroll_to_element(9, 'up')
profile_1.open_contact_from_profile(nickname)
chat_1.block_contact()
profile_1.element_by_text(nickname_after_sync).click()
chat_1.remove_from_contacts.click()
home_2.just_fyi('Contacts (secondary device): check removed and blocked contact')
home_2.element_by_text_part(nickname).wait_for_invisibility_of_element(60)
home_2.profile_button.click()
profile_2.contacts_button.click()
profile_2.element_by_text(nickname_after_sync).wait_for_invisibility_of_element(60)
device_1.just_fyi('Chats (main device):delete added public chat, (secondary device): check that synced')
for profile in (profile_1, profile_2):
profile.get_back_to_home_view()
profile.home_button.click()
home_1.delete_chat_long_press('#%s' % public_chat_after_sync)
home_2.element_by_text('#%s' % public_chat_after_sync).wait_for_invisibility_of_element(60)
self.errors.verify_no_errors()
@marks.testrail_id(6324)
@marks.medium
def test_invite_to_group_chat_handling(self):
self.create_drivers(3)
sign_ins, homes, public_keys, usernames, chats = {}, {}, {}, {}, {}
for key in self.drivers:
sign_ins[key] = SignInView(self.drivers[key])
homes[key] = sign_ins[key].create_user()
public_keys[key], usernames[key] = sign_ins[key].get_public_key_and_username(True)
sign_ins[key].home_button.click()
[driver.close_app() for driver in (self.drivers[1], self.drivers[2])]
chat_name = homes[0].get_random_chat_name()
homes[0].just_fyi('Create group chats without members')
chats[0] = homes[0].create_group_chat([], chat_name)
link = chats[0].get_group_invite_via_group_info()
chats[0].get_back_to_home_view()
chats[0].just_fyi('Member_1, member_2: both users send requests to join group chat')
[sign_in.open_weblink_and_login(link) for sign_in in (sign_ins[1], sign_ins[2])]
introduction_messages = ['message for retrying']
for i in range(1, 3):
homes[i].element_by_text_part(chat_name).click()
chats[i] = ChatView(self.drivers[i])
introduction_messages.append('Please add me, member_%s to your gorgeous group chat' % str(i))
chats[i].request_membership_for_group_chat(introduction_messages[i])
chats[0].just_fyi('Admin: accept request for Member_1 and decline for Member_2')
homes[0].get_chat(chat_name).click()
chats[0].group_membership_request_button.wait_and_click()
chats[0].element_by_text(usernames[1]).click()
if not chats[0].element_by_text_part(introduction_messages[1]).is_element_displayed():
self.errors.append('Introduction message is not shown!')
chats[0].accept_group_invitation_button.wait_and_click()
chats[0].accept_membership_for_group_chat_via_chat_view(usernames[2], accept=False)
chats[0].click_system_back_button()
chats[2].just_fyi('Member_2: retry request')
chats[2].retry_group_invite_button.wait_and_click()
chats[2].request_membership_for_group_chat(introduction_messages[0])
chats[2].just_fyi('Admin: decline request for Member_2')
chats[0].group_membership_request_button.wait_and_click()
chats[0].element_by_text(usernames[2]).click()
if not chats[0].element_by_text_part(introduction_messages[0]).is_element_displayed():
self.errors.append('Introduction message that was set after retrying attempt is not shown for admin!')
chats[0].decline_group_invitation_button.wait_and_click()
chats[0].click_system_back_button()
chats[2].just_fyi('Member_2: remove chat')
chats[2].remove_group_invite_button.wait_and_click()
chats[2].just_fyi('Double check after relogin')
if chats[0].group_membership_request_button.is_element_displayed():
self.errors.append('Group membership request is still shown when there are no pending requests anymore')
[homes[i].relogin() for i in range(0, 3)]
if homes[2].element_by_text_part(chat_name).is_element_displayed():
self.errors.append('Group chat was not removed when removing after declining group invite')
[home.get_chat(chat_name).click() for home in (homes[0], homes[1])]
if chats[0].group_membership_request_button.is_element_displayed():
self.errors.append(
'Group membership request is shown after relogin when there are no pending requests anymore')
join_system_message = chats[0].join_system_message(usernames[1])
for chat in (chats[1], chats[0]):
if not chat.chat_element_by_text(join_system_message).is_element_displayed():
self.errors.append('%s is not shown after joining to group chat via invite' % join_system_message)
self.errors.verify_no_errors()
@marks.testrail_id(4001)
@marks.medium
def test_remove_member_from_group_chat(self):
self.create_drivers(3)
homes, public_keys, usernames, chats = {}, {}, {}, {}
for key in self.drivers:
sign_in_view = SignInView(self.drivers[key])
homes[key] = sign_in_view.create_user()
public_keys[key], usernames[key] = sign_in_view.get_public_key_and_username(True)
sign_in_view.home_button.click()
chat_name = homes[0].get_random_chat_name()
for i in range(1, 3):
homes[0].add_contact(public_keys[i])
homes[0].get_back_to_home_view()
chats[0] = homes[0].create_group_chat([usernames[1],
usernames[2]], chat_name)
chats[0].just_fyi('Member_1, member_2: both users join to group chat')
for i in range(1, 3):
chats[i] = homes[i].get_chat(chat_name).click()
chats[i].join_chat_button.click()
chats[0].just_fyi("Admin: get options for device 2 in group chat and remove him")
options = chats[0].get_user_options(usernames[1])
options.remove_user_button.click()
left_message = chats[0].leave_system_message(usernames[1])
for key in chats:
if not chats[key].chat_element_by_text(left_message).is_element_displayed():
self.errors.append("Message with text '%s' was not received" % left_message)
chats[0].just_fyi("Check that input field is not available after removing")
if chats[1].chat_message_input.is_element_displayed():
self.errors.append("Message input is still available for removed user")
chats[0].just_fyi("Send message and check that it is available only for remaining users")
message = 'after removing member'
chats[0].send_message(message)
for chat in (chats[0], chats[2]):
if not chat.chat_element_by_text(message).is_element_displayed(30):
self.errors.append("Message '%s' was not received after removing member" % message)
if chats[1].chat_element_by_text(message).is_element_displayed():
self.errors.append("Message '%s' was received by removed member" % message)
self.errors.verify_no_errors()
@marks.testrail_id(6317)
@marks.medium
def test_pair_devices_group_chat_different_messages_nicknames(self):
self.create_drivers(3)
device_1, device_2, device_3 = SignInView(self.drivers[0]), SignInView(self.drivers[1]), SignInView(
self.drivers[2])
home_1 = device_1.create_user()
profile_1 = home_1.profile_button.click()
profile_1.privacy_and_security_button.click()
profile_1.backup_recovery_phrase_button.click()
profile_1.ok_continue_button.click()
recovery_phrase = profile_1.get_recovery_phrase()
profile_1.close_button.click()
profile_1.home_button.click()
home_3 = device_3.create_user()
public_key_3, username_3 = home_3.get_public_key_and_username(return_username=True)
device_3.home_button.click()
device_1_name, device_2_name, group_chat_name = 'creator', 'paired', 'some group chat'
home_2 = device_2.recover_access(passphrase=' '.join(recovery_phrase.values()))
device_1.just_fyi('Add contact, start group chat')
nickname = 'my_tester'
home_1.add_contact(public_key_3, nickname=nickname)
home_1.get_back_to_home_view()
chat_1 = home_1.create_group_chat([username_3], group_chat_name)
chat_3 = home_3.get_chat(group_chat_name).click()
chat_3.join_chat_button.click()
device_2.just_fyi('Go to profile > Devices, set device name, discover device 2 to device 1')
profile_2 = home_2.profile_button.click()
profile_2.discover_and_advertise_device(device_2_name)
device_1.profile_button.click()
profile_1.discover_and_advertise_device(device_1_name)
profile_1.get_toggle_device_by_name(device_2_name).click()
profile_1.sync_all_button.click()
profile_1.sync_all_button.wait_for_visibility_of_element(15)
profile_1.click_system_back_button(2)
device_1.just_fyi('Send message to group chat and verify it on all devices')
text_message = 'some text'
profile_1.home_button.click(desired_view='chat')
profile_2.home_button.click()
chat_1.send_message(text_message)
chat_2 = home_2.get_chat(group_chat_name).click()
for chat in chat_1, chat_2, chat_3:
if not chat.chat_element_by_text(text_message).is_element_displayed():
self.errors.append('Message was sent, but it is not shown')
device_3.just_fyi('Send message to group chat as member and verify nickname on it')
message_from_member = 'member1'
chat_3.send_message(message_from_member)
chat_1.chat_element_by_text(message_from_member).wait_for_visibility_of_element(20)
for chat in chat_1, chat_2:
if not chat.chat_element_by_text(message_from_member).username != '%s %s' % (nickname, username_3):
self.errors.append('Nickname is not shown in group chat')
device_1.just_fyi('Send image to group chat and verify it on all devices')
chat_1.show_images_button.click()
chat_1.allow_button.click()
chat_1.first_image_from_gallery.click()
chat_1.send_message_button.click()
chat_1.chat_message_input.click()
for chat in chat_1, chat_2, chat_3:
if not chat.image_message_in_chat.is_element_displayed(60):
self.errors.append('Image is not shown in chat after sending for %s' % chat.driver.number)
device_1.just_fyi('Send audio message to group chat and verify it on all devices')
chat_1.record_audio_message(message_length_in_seconds=3)
device_1.send_message_button.click()
chat_1.chat_message_input.click()
for chat in chat_1, chat_2, chat_3:
if not chat.play_pause_audio_message_button.is_element_displayed(30):
self.errors.append('Audio message is not shown in chat after sending!')
device_1.just_fyi('Send sticker to group chat and verify it on all devices')
chat_1.profile_button.click()
profile_1.switch_network()
home_1.get_chat(group_chat_name).click()
chat_1.install_sticker_pack_by_name()
chat_1.sticker_icon.click()
if not chat_1.sticker_message.is_element_displayed(30):
self.errors.append('Sticker was not sent')
self.errors.verify_no_errors()
+1 -2
View File
@@ -349,7 +349,6 @@ class SauceSharedMultipleDeviceTestCase(AbstractTestCase):
for index, driver in self.drivers.items():
jobs[driver.session_id] = index + 1
self.errors = Errors()
test_suite_data.current_test.group_name = self.__class__.__name__
def teardown_method(self, method):
geth_names, geth_contents = [], []
@@ -411,4 +410,4 @@ class NoDeviceTestCase(AbstractTestCase):
pass
def teardown_method(self, method):
self.github_report.save_test(test_suite_data.current_test)
self.github_report.save_test(test_suite_data.current_test)
File diff suppressed because it is too large Load Diff
@@ -1,207 +0,0 @@
import pytest
from tests import marks
from tests.base_test_case import MultipleSharedDeviceTestCase, create_shared_drivers
from views.sign_in_view import SignInView
from views.chat_view import ChatView
@pytest.mark.xdist_group(name="group_chat_3")
@marks.critical
@pytest.mark.run1
class TestGroupChatMultipleDeviceMerged(MultipleSharedDeviceTestCase):
@classmethod
def setup_class(cls):
cls.drivers, cls.loop = create_shared_drivers(3)
cls.message_before_adding = 'message before adding new user'
cls.message_to_admin = 'Hey, admin!'
cls.homes, cls.public_keys, cls.usernames, cls.chats = {}, {}, {}, {}
for key in cls.drivers:
sign_in = SignInView(cls.drivers[key])
cls.homes[key] = sign_in.create_user(enable_notifications=True)
cls.public_keys[key], cls.usernames[key] = sign_in.get_public_key_and_username(True)
sign_in.home_button.click()
cls.chat_name = cls.homes[0].get_random_chat_name()
cls.homes[0].just_fyi('Admin adds future members to contacts')
for i in range(1, 3):
cls.homes[0].add_contact(cls.public_keys[i])
cls.homes[0].home_button.double_click()
cls.homes[0].just_fyi('Member adds admin to contacts to see PNs and put app in background')
cls.homes[1].add_contact(cls.public_keys[0])
cls.homes[1].home_button.double_click()
cls.homes[0].just_fyi('Admin creates group chat')
cls.chats[0] = cls.homes[0].create_group_chat([cls.usernames[1]], cls.chat_name)
for i in range(1, 3):
cls.chats[i] = ChatView(cls.drivers[i])
cls.chats[0].send_message(cls.message_before_adding)
@marks.testrail_id(3994)
def test_group_chat_push_system_messages_when_invited(self):
self.homes[1].just_fyi("Check system messages in PNs")
self.homes[1].put_app_to_background()
self.homes[1].open_notification_bar()
pns = [self.chats[0].pn_invited_to_group_chat(self.usernames[0], self.chat_name),
self.chats[0].pn_wants_you_to_join_to_group_chat(self.usernames[0], self.chat_name)]
for pn in pns:
if not self.homes[1].get_pn(pn):
self.errors.append('%s is not shown after invite to group chat' % pn)
if self.homes[1].get_pn(pns[0]):
group_invite_pn = self.homes[1].get_pn(pns[0])
group_invite_pn.click()
else:
self.homes[1].click_system_back_button(2)
self.homes[1].get_chat(self.chat_name).click()
self.homes[1].just_fyi("Check system messages in group chat for admin and member")
create_system_message = self.chats[0].create_system_message(self.usernames[0], self.chat_name)
invite_system_message = self.chats[0].invite_system_message(self.usernames[0], self.usernames[1])
invited_to_join = self.chats[0].invited_to_join_system_message(self.usernames[0], self.chat_name)
create_for_admin_system_message = self.chats[0].create_for_admin_system_message(self.chat_name)
for message in [create_for_admin_system_message, create_system_message, invite_system_message]:
if not self.chats[0].chat_element_by_text(message):
self.errors.append('%s system message is not shown' % message)
for message in [invited_to_join, create_system_message, invite_system_message]:
if not self.chats[1].chat_element_by_text(message):
self.errors.append('%s system message is not shown' % message)
self.errors.verify_no_errors()
@marks.testrail_id(700731)
def test_group_chat_join_send_text_messages_push(self):
message_to_admin = self.message_to_admin
[self.homes[i].home_button.double_click() for i in range(3)]
self.homes[1].get_chat(self.chat_name).click()
self.chats[1].just_fyi('Join to group chat')
join_system_message = self.chats[1].join_system_message(self.usernames[1])
self.chats[1].join_chat_button.click()
if not self.chats[1].chat_element_by_text(join_system_message).is_element_displayed(30):
self.drivers[1].fail('System message after joining group chat is not shown')
self.chats[1].send_message(message_to_admin)
self.chats[0].just_fyi('check that PN is received and after tap you are redirected to group chat')
self.chats[0].open_notification_bar()
pn = self.homes[0].get_pn(message_to_admin)
if pn:
pn.click()
else:
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')
message_status = self.chats[1].chat_element_by_text(message_to_admin).status
if message_status != 'delivered':
self.errors.append('Message status is not delivered, it is %s!' % message_status)
for message in (join_system_message, message_to_admin):
if not self.chats[0].chat_element_by_text(message).is_element_displayed(30):
self.drivers[0].fail('Message %s was not received by admin' % message)
self.errors.verify_no_errors()
@marks.testrail_id(700732)
def test_group_chat_add_new_member_activity_centre(self):
[self.homes[i].home_button.double_click() for i in range(3)]
self.homes[0].get_chat(self.chat_name).click()
self.chats[0].add_members_to_group_chat([self.usernames[2]])
self.chats[2].just_fyi("Check there will be no PN but unread in AC if got invite from non-contact")
if not self.homes[2].notifications_unread_badge.is_element_displayed(60):
self.drivers[2].fail("Group chat is not appeared in AC!")
self.homes[2].open_notification_bar()
if self.homes[2].element_by_text_part(self.usernames[0]).is_element_displayed():
self.errors.append("PN about group chat invite is shown when invited by non-contact")
self.homes[2].click_system_back_button()
self.homes[2].get_chat(self.chat_name).click()
self.chats[2].join_chat_button.click()
for message in (self.message_to_admin, self.message_before_adding):
if self.chats[2].chat_element_by_text(message).is_element_displayed():
self.errors.append('%s is shown for new user' % message)
self.errors.verify_no_errors()
@marks.testrail_id(3998)
def test_group_chat_offline_pn(self):
[self.homes[i].home_button.double_click() for i in range(3)]
chat_name = 'for_offline_pn'
self.homes[0].create_group_chat([self.usernames[1], self.usernames[2]], chat_name)
self.homes[0].home_button.double_click()
for i in range(1, 3):
self.homes[i].get_chat(chat_name).click()
self.chats[i].join_chat_button.click()
message_1, message_2 = 'message from old member', 'message from new member'
self.homes[0].just_fyi("Put admin device to offline and send messages from members")
self.homes[0].toggle_airplane_mode()
self.chats[1].send_message(message_1)
self.chats[2].send_message(message_2)
self.homes[0].just_fyi("Put admin device to online and check that messages and PNs will be fetched")
self.homes[0].toggle_airplane_mode()
self.homes[0].connection_offline_icon.wait_for_invisibility_of_element(60)
self.homes[0].open_notification_bar()
for message in (message_1, message_2):
if not self.homes[0].get_pn(message):
self.errors.append('%s PN was not fetched from offline' % message)
self.homes[0].click_system_back_button()
unread_group = self.homes[0].get_chat(chat_name)
if not unread_group.new_messages_counter.text == '2':
self.errors.append('%s does not match unread messages' % unread_group.new_messages_counter.text)
unread_group.click()
self.homes[0].just_fyi("check that messages are shown for every member")
for i in range(3):
for message in (message_1, message_2):
if not self.chats[i].chat_element_by_text(message).is_element_displayed():
self.errors.append('%s if not shown for device %s' % (message, str(i)))
self.errors.verify_no_errors()
@marks.testrail_id(5756)
def test_group_chat_decline_invite_chat_highligted(self):
chat_name = 'for_invited'
left_system_message = self.chats[0].leave_system_message(self.usernames[1])
[self.homes[i].home_button.double_click() for i in range(3)]
self.homes[0].create_group_chat([self.usernames[1]], chat_name)
self.homes[1].just_fyi("Check that new group chat from contact is highlited")
chat_2_element = self.homes[1].get_chat(chat_name)
if chat_2_element.no_message_preview.is_element_differs_from_template('highligted_preview_group.png', 0):
self.errors.append("Preview message is not hightligted or text is not shown! ")
chat_2 = self.homes[1].get_chat(chat_name).click()
chat_2.home_button.click()
if not chat_2_element.no_message_preview.is_element_differs_from_template('highligted_preview_group.png', 0):
self.errors.append("Preview message is still hightligted after opening! ")
self.homes[1].get_chat(chat_name).click()
chat_2.decline_invitation_button.click()
if self.chats[0].chat_element_by_text(left_system_message).is_element_displayed():
self.errors.append('System message when user declined invite is shown')
if self.homes[1].element_by_text(chat_name).is_element_displayed():
self.errors.append("Group chat '%s' is shown, but user declined invite" % chat_name)
self.homes[0].just_fyi('Send message after invite is declined and check that it is not reappeared')
message = 'sent after leaving'
self.chats[0].send_message(message)
if self.homes[1].element_by_text(chat_name).is_element_displayed():
self.errors.append("Group chat '%s' reappeared when new message is sent" % chat_name)
self.errors.verify_no_errors()
@marks.testrail_id(3997)
def test_group_chat_leave_relogin(self):
self.drivers[2].quit()
[self.homes[i].home_button.double_click() for i in range(2)]
self.homes[0].home_button.double_click()
self.homes[1].get_chat(self.chat_name).click()
join_button = self.chats[1].join_chat_button
if join_button.is_element_displayed():
join_button.click()
self.homes[0].just_fyi("Admin deleted chat via long press")
self.homes[0].leave_chat_long_press(self.chat_name)
self.homes[0].just_fyi("Member sends some message, admin relogins and check chat does not reappear")
self.chats[1].send_message(self.message_to_admin)
self.homes[0].relogin()
if self.homes[0].get_chat_from_home_view(self.chat_name).is_element_displayed():
self.drivers[0].fail('Deleted %s is present after relaunch app' % self.chat_name)
@@ -1,254 +0,0 @@
import pytest
from tests import marks
from tests.base_test_case import MultipleSharedDeviceTestCase, create_shared_drivers
from tests.users import transaction_senders, basic_user, ens_user, ens_user_ropsten
from views.sign_in_view import SignInView
# TODO: suspended according to #13257
@pytest.mark.xdist_group(name="pairing_2")
@marks.critical
@marks.skip
class TestPairingMultipleDevicesMerged(MultipleSharedDeviceTestCase):
@classmethod
def setup_class(cls):
from views.dbs.main_pairing.data import seed_phrase, password
cls.drivers, cls.loop = create_shared_drivers(2)
cls.device_1, cls.device_2 = SignInView(cls.drivers[0]), SignInView(cls.drivers[1])
cls.home_1 = cls.device_1.import_db(seed_phrase=seed_phrase, import_db_folder_name='main_pairing',
password=password)
cls.home_2 = cls.device_2.recover_access(seed_phrase)
cls.home_1.just_fyi('Pair main and secondary devices')
[cls.profile_1, cls.profile_2] = [home.profile_button.click() for home in (cls.home_1, cls.home_2)]
name_1, name_2 = 'device_1', 'a_%s_2' % cls.device_2.get_unique_amount()
cls.profile_2.discover_and_advertise_device(name_2)
cls.profile_1.sync_settings_button.scroll_and_click()
cls.profile_1.devices_button.scroll_to_element()
cls.profile_1.devices_button.click()
cls.home_1.element_by_text_part(name_2).scroll_and_click()
cls.profile_1.sync_all_button.click()
cls.profile_1.sync_all_button.wait_for_visibility_of_element(20)
[profile.get_back_to_home_view() for profile in [cls.profile_1, cls.profile_2]]
[home.home_button.click() for home in [cls.home_1, cls.home_2]]
def test_pairing_initial_sync_chats(self):
self.profile_2.just_fyi("Check chats and previews")
from views.dbs.main_pairing.data import chats
for chat in chats.keys():
if chats[chat]['initial_sync']:
if 'preview' in chats.keys():
actual_chat_preview = self.home_2.get_chat(chat).chat_preview.text
expected_chat_preview = chats[chat]['preview']
if actual_chat_preview != expected_chat_preview:
self.errors.append('Expected preview for %s is "%s", in fact "%s" after initial sync' %
(chat, expected_chat_preview, actual_chat_preview))
# TODO: blocked due to 13176
# self.profile_2.just_fyi("Check unread indicator")
# if self.home_2.home_button.counter.text != '2':
# self.errors.append('New messages counter is not shown on Home button')
# for chat in chats.keys():
# if 'unread' in chats.keys():
# if self.home_2.get_chat(chat).new_messages_counter.text != chats[chat]['unread']:
# self.errors.append('No unread for %s after initial sync' % chat)
self.errors.verify_no_errors()
@marks.skip
# TODO: blocked due to 13176
def test_pairing_initial_sync_activity_centre(self):
from views.dbs.main_pairing.data import activity_centre
if self.home_2.notifications_unread_badge.is_element_displayed():
self.home_2.notifications_unread_badge.click()
for chat in activity_centre.keys():
from views.home_view import ActivityCenterChatElement
chat_in_ac = ActivityCenterChatElement(self.driver, chat_name=chat)
if not chat_in_ac.is_element_displayed():
self.errors.append('No chat "%s" in activity centre' % chat)
else:
if not chat_in_ac.chat_message_preview != activity_centre[chat]:
self.errors.append('No chat preview for "%s" in activity centre, "%s" instead' %
chat, chat_in_ac.chat_message_preview)
else:
self.home_2.driver.fail("No unread messages in Activity centre!")
self.errors.verify_no_errors()
def test_pairing_initial_sync_contacts_blocked_nickname(self):
from views.dbs.main_pairing.data import contacts, blocked
self.profile_2 = self.home_2.profile_button.click()
self.profile_2.contacts_button.click()
for contact in contacts:
if not self.profile_2.element_by_text(contact).is_element_displayed():
self.errors.append("%s contact is not synced after initial sync" % contact)
self.profile_2.blocked_users_button.click()
for blocked_user in blocked.keys():
if not self.profile_2.element_by_text(blocked_user).is_element_displayed():
self.errors.append("%s blocked user is not synced after initial sync" % blocked_user)
self.profile_2.get_back_to_home_view()
@pytest.mark.xdist_group(name="sync_2")
@marks.critical
@pytest.mark.run1
class TestPairingSyncMultipleDevicesMerged(MultipleSharedDeviceTestCase):
@classmethod
def setup_class(cls):
cls.drivers, cls.loop = create_shared_drivers(2)
cls.no_contact_nickname = 'no_contact_nickname'
cls.device_1, cls.device_2 = SignInView(cls.drivers[0]), SignInView(cls.drivers[1])
cls.home_1 = cls.device_1.create_user()
cls.name_1, cls.name_2 = 'device_%s' % cls.drivers[0].number, 'device_%s' % cls.drivers[1].number
cls.message_before_sync, cls.message_after_sync = 'sent before sync', 'sent after sync'
cls.contact_before_sync = basic_user
cls.public_chat_before_sync, cls.public_chat_after_sync = cls.home_1.get_random_chat_name(), 'after-pairing'
cls.home_1.just_fyi("(main device): get recovery phrase")
cls.profile_1 = cls.home_1.profile_button.click()
cls.profile_1.privacy_and_security_button.click()
cls.profile_1.backup_recovery_phrase_button.click()
cls.profile_1.ok_continue_button.click()
cls.recovery_phrase = cls.profile_1.get_recovery_phrase()
cls.profile_1.close_button.click()
cls.profile_1.home_button.click()
cls.profile_1.get_recovery_phrase()
cls.home_1.just_fyi('Add contact, 1-1 chat (main device): 3-random, contact with ENS, start 1-1')
cls.chat_1 = cls.home_1.add_contact(cls.contact_before_sync['public_key'])
cls.chat_1.send_message(cls.message_before_sync)
cls.chat_1.home_button.click()
cls.home_1.add_contact(ens_user['ens'])
cls.chat_1.home_button.click()
cls.home_1.just_fyi('Chats, contacts (main device): join public chat, block user, set nickname')
public_chat_1 = cls.home_1.join_public_chat(cls.public_chat_before_sync)
public_chat_1.home_button.click()
cls.home_1.add_contact(transaction_senders['A']['public_key'], add_in_contacts=False,
nickname=cls.no_contact_nickname)
cls.chat_1.open_user_profile_from_1_1_chat()
cls.chat_1.block_contact()
cls.device_2.just_fyi("(secondary device): restore same multiaccount on another device")
cls.home_2 = cls.device_2.recover_access(passphrase=' '.join(cls.recovery_phrase.values()))
cls.profile_1, cls.profile_2 = cls.home_1.profile_button.click(), cls.home_2.profile_button.click()
cls.device_2.just_fyi('Nicknames (main device): set nickname for contact')
cls.profile_1.open_contact_from_profile(cls.contact_before_sync['username'])
cls.nickname = 'my_basic_user'
cls.chat_1.set_nickname(cls.nickname)
cls.device_1.back_button.click()
cls.device_2.just_fyi('Pair main and secondary devices')
cls.profile_2.discover_and_advertise_device(cls.name_2)
cls.profile_1.discover_and_advertise_device(cls.name_1)
cls.profile_1.get_toggle_device_by_name(cls.name_2).wait_and_click()
cls.profile_1.sync_all_button.click()
cls.profile_1.sync_all_button.wait_for_visibility_of_element(20)
[device.profile_button.double_click() for device in (cls.profile_1, cls.profile_2)]
@marks.testrail_id(702194)
def test_pairing_sync_initial_contacts_blocked_users(self):
self.profile_2.contacts_button.scroll_to_element(9, 'up')
self.profile_2.contacts_button.click()
if not self.profile_2.blocked_users_button.is_element_displayed(30):
self.errors.append('Blocked users are not synced after initial sync')
for name in (basic_user['username'], self.nickname, '@%s' % ens_user['ens']):
if not self.profile_2.element_by_text(name).is_element_displayed():
self.errors.append('"%s" is not found in Contacts on initial sync' % name)
self.profile_2.blocked_users_button.click()
if not self.profile_2.element_by_text(self.no_contact_nickname).is_element_displayed():
self.errors.append(
"'%s' nickname without adding to contacts is not synced on initial sync" % self.no_contact_nickname)
self.errors.verify_no_errors()
@marks.testrail_id(702195)
def test_pairing_sync_initial_public_chats(self):
[device.home_button.double_click() for device in (self.profile_1, self.profile_2)]
if not self.home_2.element_by_text_part(self.public_chat_before_sync).is_element_displayed():
self.errors.append(
"'%s' public chat is not appeared on secondary device on initial sync" % self.public_chat_before_sync)
self.errors.verify_no_errors()
@marks.testrail_id(702196)
def test_pairing_sync_contacts_block_unblock(self):
[device.profile_button.double_click() for device in (self.profile_1, self.profile_2)]
new_user_for_block = transaction_senders['C']
self.profile_1.just_fyi("Contacts(main device): block and unblock user")
self.profile_1.profile_button.click()
self.profile_1.contacts_button.scroll_to_element(direction='up')
self.profile_1.contacts_button.click()
self.profile_1.blocked_users_button.click()
self.profile_1.element_by_text(self.no_contact_nickname).click()
self.chat_1.unblock_contact_button.click()
self.profile_1.close_button.click()
self.home_1.home_button.click()
self.home_1.add_contact(new_user_for_block['public_key'], add_in_contacts=False)
self.chat_1.open_user_profile_from_1_1_chat()
self.chat_1.block_contact()
self.device_2.just_fyi('Contacts (secondary device): check unblocked and blocked user')
self.profile_2.contacts_button.click()
self.profile_2.blocked_users_button.click()
if self.profile_2.element_by_text(self.no_contact_nickname).is_element_displayed():
self.errors.append("'%s' unblocked user is not synced!" % self.no_contact_nickname)
if not self.profile_2.element_by_text(new_user_for_block['username']).is_element_displayed():
self.errors.append("'%s' blocked user is not synced!" % new_user_for_block['username'])
self.errors.verify_no_errors()
@marks.testrail_id(702197)
def test_pairing_sync_contacts_add_remove_set_nickname_ens(self):
[device.home_button.double_click() for device in (self.profile_1, self.profile_2)]
new_contact, new_nickname = transaction_senders['F'], "completely_new_nick"
self.home_1.add_contact(ens_user_ropsten['ens'])
self.home_1.home_button.click()
self.home_1.add_contact(new_contact['public_key'])
self.device_2.just_fyi('Contacts (secondary device):check new contact')
self.profile_2.profile_button.double_click()
self.profile_2.contacts_button.scroll_to_element(direction='up')
self.profile_2.contacts_button.click()
for contact in (new_contact['username'], '@%s' % ens_user_ropsten['ens']):
if not self.profile_2.element_by_text(contact).is_element_displayed():
self.errors.append("'%s' new contact is not synced!" % contact)
self.device_1.just_fyi('(Main device): set nickname, (secondary device): check nickname')
self.chat_1.open_user_profile_from_1_1_chat()
self.chat_1.set_nickname(new_nickname)
if not self.profile_2.element_by_text(new_nickname).is_element_displayed():
self.errors.append("'%s' new nickname is not synced!" % new_nickname)
self.device_1.just_fyi('(Main device): remove contact, (secondary device): check removed contact')
self.chat_1.open_user_profile_from_1_1_chat()
self.chat_1.remove_from_contacts.click()
self.chat_1.close_button.click()
self.profile_2.element_by_text(new_nickname).is_element_disappeared(40)
self.errors.verify_no_errors()
@marks.testrail_id(702198)
def test_pairing_sync_1_1_chat_message(self):
[device.home_button.double_click() for device in (self.profile_1, self.profile_2)]
self.home_1.get_chat(self.nickname).click()
self.chat_1.send_message(self.message_after_sync)
self.home_2.just_fyi("Chats (secondary device): check messages in 1-1")
chat = self.home_2.get_chat(self.nickname).click()
if chat.chat_element_by_text(self.message_before_sync).is_element_displayed():
self.errors.append('"%s" message sent before pairing is synced' % self.message_before_sync)
if not chat.chat_element_by_text(self.message_after_sync).is_element_displayed(60):
self.errors.append('"%s" message in 1-1 is not synced' % self.message_after_sync)
self.errors.verify_no_errors()
@marks.testrail_id(702199)
def test_pairing_sync_public_chat_add_remove(self):
[device.home_button.double_click() for device in (self.profile_1, self.profile_2)]
self.home_1.join_public_chat(self.public_chat_after_sync)
if not self.home_2.element_by_text("#%s" % self.public_chat_after_sync).is_element_displayed(10):
self.errors.append('Public chat "%s" is not synced' % self.public_chat_after_sync)
self.home_1.home_button.click()
self.home_1.delete_chat_long_press('#%s' % self.public_chat_after_sync)
if not self.home_2.element_by_text('#%s' % self.public_chat_after_sync).is_element_disappeared(60):
self.errors.append('Remove of "%s" public chat is not synced!' % self.public_chat_after_sync)
self.errors.verify_no_errors()
@@ -1,480 +0,0 @@
import random
import pytest
from support.utilities import get_merged_txs_list
from tests import marks, common_password, pin, puk, pair_code
from tests.base_test_case import MultipleSharedDeviceTestCase, create_shared_drivers
from tests.users import transaction_senders, basic_user, wallet_users, ens_user_ropsten, ens_user
from views.sign_in_view import SignInView
@pytest.mark.xdist_group(name="send_tx_1")
@marks.critical
@pytest.mark.run1
class TestSendTxDeviceMerged(MultipleSharedDeviceTestCase):
@classmethod
def setup_class(cls):
cls.user = transaction_senders['ETH_ADI_STT_3']
cls.recipient_address = '0x%s' % transaction_senders['ETH_7']['address']
cls.drivers, cls.loop = create_shared_drivers(1)
[cls.amount_adi, cls.amount_eth, cls.amount_stt] = ['0.000%s' % str(random.randint(100, 999)) + '1' for _ in range(3)]
cls.sign_in = SignInView(cls.drivers[0])
cls.home = cls.sign_in.recover_access(cls.user['passphrase'])
cls.wallet = cls.home.wallet_button.click()
cls.assets = ('ETH', 'ADI', 'STT')
[cls.wallet.wait_balance_is_changed(asset) for asset in cls.assets]
cls.initial_balances = dict()
for asset in cls.assets:
cls.initial_balances[asset] = cls.wallet.get_asset_amount_by_name(asset)
cls.wallet.send_transaction(amount=cls.amount_eth, recipient=cls.recipient_address)
cls.wallet.send_transaction(amount=cls.amount_adi, recipient=cls.recipient_address, asset_name='ADI')
@marks.testrail_id(700763)
def test_send_tx_eth_check_logcat(self):
self.wallet.just_fyi('Check that transaction is appeared in tx history')
self.wallet.find_transaction_in_history(amount=self.amount_eth)
self.wallet.wallet_button.double_click()
self.network_api.wait_for_confirmation_of_transaction(self.user['address'], self.amount_eth)
self.wallet.wait_balance_is_changed('ETH', initial_balance=self.initial_balances['ETH'])
self.wallet.just_fyi('Check logcat for sensitive data')
values_in_logcat = self.wallet.find_values_in_logcat(password=common_password)
if values_in_logcat:
self.wallet.driver.fail(values_in_logcat)
@marks.testrail_id(700764)
def test_send_tx_token_7_decimals(self):
asset = 'ADI'
self.wallet.just_fyi("Checking tx with 7 decimals")
transaction_adi = self.wallet.find_transaction_in_history(amount=self.amount_adi, asset=asset, return_hash=True)
self.wallet.wallet_button.double_click()
self.network_api.find_transaction_by_hash(transaction_adi)
self.wallet.wait_balance_is_changed(asset, initial_balance=self.initial_balances[asset])
@marks.testrail_id(5342)
def test_send_tx_sign_message_2tx_in_batch_tx_filters_request_stt_testdapp(self):
self.wallet.home_button.click()
status_test_dapp = self.home.open_status_test_dapp()
status_test_dapp.wait_for_d_aap_to_load()
self.wallet.just_fyi("Checking request STT")
status_test_dapp.assets_button.click()
status_test_dapp.request_stt_button.wait_for_element(60)
send_transaction = status_test_dapp.request_stt_button.click()
send_transaction.sign_transaction()
self.wallet.just_fyi("Checking signing message")
status_test_dapp.transactions_button.click()
send_transaction = status_test_dapp.sign_message_button.click()
send_transaction.enter_password_input.set_value(common_password)
send_transaction.sign_button.click()
if not status_test_dapp.element_by_text_part('Signed message').is_element_displayed():
self.errors.append('Message was not signed')
send_transaction.just_fyi('Check logcat for sensitive data')
values_in_logcat = send_transaction.find_values_in_logcat(password=common_password)
if values_in_logcat:
self.errors.append("When signing message from dapp: %s" % values_in_logcat)
self.wallet.just_fyi("Checking send 2 txs in batch")
status_test_dapp.send_two_tx_in_batch_button.scroll_to_element()
send_transaction = status_test_dapp.send_two_tx_in_batch_button.click()
send_transaction.sign_transaction()
if not send_transaction.sign_with_password.is_element_displayed(10):
self.errors.append('Second send transaction screen did not appear!')
send_transaction.sign_transaction()
self.wallet.just_fyi("Checking send 2 txs one after another")
status_test_dapp.send_two_tx_one_by_one_button.scroll_to_element()
send_transaction = status_test_dapp.send_two_tx_one_by_one_button.click()
send_transaction.sign_transaction()
if not send_transaction.sign_with_password.is_element_displayed(20):
self.errors.append('Second send transaction screen did not appear!')
send_transaction.sign_transaction()
self.wallet.just_fyi("Checking test filters")
status_test_dapp.test_filters_button.scroll_and_click()
for element in status_test_dapp.element_by_text('eth_uninstallFilter'), status_test_dapp.ok_button:
if element.is_element_displayed(10):
self.errors.append("'Test filters' button produced an error")
self.errors.verify_no_errors()
@marks.testrail_id(700765)
def test_send_tx_custom_token_18_decimals_invalid_password(self):
contract_address, name, symbol, decimals = '0x101848D5C5bBca18E6b4431eEdF6B95E9ADF82FA', 'Weenus 💪', 'WEENUS', '18'
self.home.wallet_button.double_click()
self.wallet.just_fyi("Check that can add custom token")
self.wallet.multiaccount_more_options.click()
self.wallet.manage_assets_button.click()
token_view = self.wallet.add_custom_token_button.click()
token_view.contract_address_input.send_keys(contract_address)
if token_view.name_input.text != name:
self.errors.append('Name for custom token was not set')
if token_view.symbol_input.text != symbol:
self.errors.append('Symbol for custom token was not set')
if token_view.decimals_input.text != decimals:
self.errors.append('Decimals for custom token was not set')
token_view.add_button.click()
token_view.close_button.click()
self.wallet.asset_by_name(symbol).scroll_to_element()
if not self.wallet.asset_by_name(symbol).is_element_displayed():
self.errors.append('Custom token is not shown on Wallet view')
send_tx = self.wallet.send_transaction_from_main_screen.click()
send_tx.select_asset_button.click()
asset_button = send_tx.asset_by_name(symbol)
send_tx.select_asset_button.click_until_presence_of_element(
send_tx.eth_asset_in_select_asset_bottom_sheet_button)
asset_button.click()
send_tx.amount_edit_box.click()
send_tx.amount_edit_box.set_value(self.amount_eth)
send_tx.set_recipient_address(self.recipient_address)
send_tx.sign_transaction_button.click()
if self.wallet.sign_in_phrase.is_element_displayed():
self.wallet.set_up_wallet_when_sending_tx()
send_tx.just_fyi('Check that can not sign tx with invalid password')
self.wallet.next_button.click_if_shown()
self.wallet.ok_got_it_button.click_if_shown()
send_tx.sign_with_password.click_until_presence_of_element(send_tx.enter_password_input)
send_tx.enter_password_input.click()
send_tx.enter_password_input.send_keys('wrong_password')
send_tx.sign_button.click()
if send_tx.element_by_text_part('Transaction sent').is_element_displayed():
self.errors.append('Transaction was sent with a wrong password')
self.wallet.just_fyi("Check that can send tx with custom token")
send_tx.enter_password_input.click()
send_tx.enter_password_input.clear()
send_tx.enter_password_input.send_keys(common_password)
send_tx.sign_button.click_until_absense_of_element(send_tx.sign_button)
send_tx.ok_button.wait_for_element(120)
if not self.wallet.element_by_translation_id("transaction-sent").is_element_displayed():
self.errors.append("Tx is not sent!")
send_tx.ok_button.click()
# TODO: disabled due to 10838 (rechecked 23.11.21, valid)
# transactions_view = wallet.transaction_history_button.click()
# transactions_view.transactions_table.find_transaction(amount=amount, asset=symbol)
self.errors.verify_no_errors()
@marks.testrail_id(700757)
def test_send_tx_set_recipient_options(self):
nickname = 'my_some_nickname'
account_name = 'my_acc_name'
account_address = '0x8c2E3Cd844848E79cFd4671cE45C12F210b630d7'
recent_add_to_fav_name = 'my_Recent_STT'
recent_add_to_fav_address = '0x58d8c3d70ce4fa4b9fb10a665c8712238746f2ff'
ens_status, ens_other = ens_user_ropsten, ens_user
basic_add_to_fav_name = 'my_basic_address'
self.drivers[0].reset()
self.home = self.sign_in.recover_access(wallet_users['D']['passphrase'])
self.home.just_fyi('Add new account and new ENS contact for recipient')
chat = self.home.add_contact(ens_status['ens'])
chat.chat_options.click()
chat.view_profile_button.click_until_presence_of_element(chat.remove_from_contacts)
chat.set_nickname(nickname)
wallet = self.home.wallet_button.click()
wallet.add_account(account_name=account_name)
wallet.accounts_status_account.click()
send_tr = wallet.send_transaction_button.click()
wallet.just_fyi("Check that can't send to invalid address")
send_tr.amount_edit_box.click()
send_tr.amount_edit_box.set_value(send_tr.get_unique_amount())
send_tr.chose_recipient_button.click()
for address in (basic_user['public_key'], '0xDE709F2102306220921060314715629080E2fB77'):
send_tr.enter_recipient_address_input.set_value(address)
send_tr.enter_recipient_address_input.click()
send_tr.done_button.click()
if send_tr.set_max_button.is_element_displayed():
self.errors.append('Can proceed with wrong address %s in recipient' % address)
send_tr.just_fyi('Set one of my accounts')
send_tr.chose_recipient_button.click_if_shown()
send_tr.element_by_translation_id("my-accounts").click()
send_tr.element_by_text(account_name).click()
if send_tr.enter_recipient_address_text.text != send_tr.get_formatted_recipient_address(account_address):
self.errors.append('Added account is not resolved as recipient')
send_tr.just_fyi('Set contract address from recent and check smart contract error')
send_tr.chose_recipient_button.click()
send_tr.element_by_translation_id("recent").click()
send_tr.element_by_text('↓ 1000 MDS').click()
if not send_tr.element_by_translation_id("warning-sending-to-contract-descr").is_element_displayed():
self.driver.fail('No warning is shown at attempt to set as recipient smart contract')
send_tr.ok_button.click()
send_tr.element_by_text('↑ 0.001 ETHro').scroll_and_click()
send_tr.add_to_favorites(recent_add_to_fav_name)
wallet.element_by_translation_id("recent").click()
send_tr.just_fyi('Scan invalid QR')
send_tr.scan_qr_code_button.click()
send_tr.allow_button.click(1)
wallet.enter_qr_edit_box.scan_qr('something%s' % basic_user['address'])
if not send_tr.element_by_text_part('Invalid address').is_element_displayed(10):
self.driver.fail('No error is shown at attempt to scan invalid address')
wallet.ok_button.click()
send_tr.just_fyi('Scan code, add it to favorites and recheck that it is preserved')
send_tr.scan_qr_code_button.click()
wallet.enter_qr_edit_box.scan_qr(basic_user['address'])
send_tr.add_to_favorites(basic_add_to_fav_name)
send_tr.element_by_translation_id("favourites").scroll_and_click()
for name in (recent_add_to_fav_name, basic_add_to_fav_name):
wallet.element_by_text(name).scroll_to_element()
send_tr.element_by_text(recent_add_to_fav_name).scroll_and_click()
if str(send_tr.enter_recipient_address_text.text).lower() != send_tr.get_formatted_recipient_address(
recent_add_to_fav_address):
self.errors.append('Recent address that was added to favourites was not resolved correctly')
send_tr.just_fyi('Set contact')
send_tr.chose_recipient_button.click()
send_tr.element_by_translation_id("contacts").scroll_and_click()
send_tr.element_by_text(nickname).scroll_and_click()
send_tr.recipient_done.click()
if send_tr.enter_recipient_address_text.text != send_tr.get_formatted_recipient_address(ens_status['address']):
self.errors.append('ENS from contact is not resolved as recipient')
send_tr.just_fyi('Set different ENS options')
send_tr.set_recipient_address(ens_other['ens_another'])
if send_tr.enter_recipient_address_text.text != send_tr.get_formatted_recipient_address(ens_other['address']):
self.errors.append('ENS address on another domain is not resolved as recipient')
send_tr.set_recipient_address('%s.stateofus.eth' % ens_status['ens'])
if send_tr.enter_recipient_address_text.text != send_tr.get_formatted_recipient_address(ens_status['address']):
self.errors.append('ENS address on stateofus.eth is not resolved as recipient')
send_tr.just_fyi('Check search and set address from search')
send_tr.chose_recipient_button.click()
send_tr.search_by_keyword(ens_status['ens'][:2])
if not send_tr.element_by_text('@' + ens_status['ens']).is_element_displayed():
self.errors.append('ENS address from contacts is not shown in search')
send_tr.cancel_button.click()
send_tr.search_by_keyword('my')
for name in (nickname, account_name, recent_add_to_fav_name, basic_add_to_fav_name):
if not send_tr.element_by_text(name).is_element_displayed():
self.errors.append('%s is not shown in search when searching by namepart' % name)
send_tr.element_by_text(basic_add_to_fav_name).click()
if send_tr.enter_recipient_address_text.text != send_tr.get_formatted_recipient_address(
'0x' + basic_user['address']):
self.errors.append('QR scanned address that was added to favourites was not resolved correctly')
self.errors.verify_no_errors()
@pytest.mark.xdist_group(name="keycard_tx_1")
@marks.critical
@pytest.mark.run1
class TestKeycardTxOneDeviceMerged(MultipleSharedDeviceTestCase):
@classmethod
def setup_class(cls):
cls.user = transaction_senders['ETH_STT_ADI_1']
cls.address = '0x%s' % transaction_senders['ETH_7']['address']
cls.drivers, cls.loop = create_shared_drivers(1)
cls.sign_in = SignInView(cls.drivers[0])
cls.home = cls.sign_in.recover_access(passphrase=cls.user['passphrase'], keycard=True)
cls.wallet = cls.home.wallet_button.click()
cls.assets = ('ETH', 'ADI', 'STT')
[cls.wallet.wait_balance_is_changed(asset) for asset in cls.assets]
cls.initial_balances = dict()
for asset in cls.assets:
cls.initial_balances[asset] = cls.wallet.get_asset_amount_by_name(asset)
@marks.testrail_id(700767)
def test_keycard_send_tx_eth(self):
wallet = self.home.wallet_button.click()
transaction_amount = wallet.get_unique_amount()
wallet.send_transaction(amount=transaction_amount, sign_transaction=True, keycard=True,
recipient=self.address)
wallet.just_fyi('Check that transaction is appeared in transaction history')
transaction = wallet.find_transaction_in_history(amount=transaction_amount, return_hash=True)
self.wallet.wallet_button.double_click()
self.network_api.find_transaction_by_hash(transaction)
self.network_api.wait_for_confirmation_of_transaction(self.user['address'], transaction_amount)
self.wallet.wait_balance_is_changed('ETH', initial_balance=self.initial_balances['ETH'])
@marks.testrail_id(700768)
def test_keycard_relogin_after_restore(self):
self.sign_in.just_fyi('Check that username and public key match expected')
public_key, default_username = self.sign_in.get_public_key_and_username(return_username=True)
profile = self.sign_in.get_profile_view()
if public_key != self.user['public_key']:
self.errors.append('Public key %s does not match expected' % public_key)
if default_username != self.user['username']:
self.errors.append('Default username %s does not match expected' % default_username)
profile.logout()
self.sign_in.just_fyi('Check that can login with restored from mnemonic keycard account')
self.sign_in.sign_in(keycard=True)
if not self.sign_in.home_button.is_element_displayed(10):
self.sign_in.driver.fail('Keycard user is not logged in')
self.errors.verify_no_errors()
@marks.testrail_id(700769)
def test_keycard_send_tx_sign_message_request_stt_testdapp(self):
self.home.home_button.double_click()
status_test_dapp = self.home.open_status_test_dapp()
status_test_dapp.wait_for_d_aap_to_load()
self.wallet.just_fyi("Requesting STT in dapp")
status_test_dapp.assets_button.click()
send_tx = status_test_dapp.request_stt_button.click()
send_tx.sign_transaction(keycard=True)
self.wallet.just_fyi("Checking signing message")
status_test_dapp.transactions_button.click()
status_test_dapp.sign_message_button.click()
if not send_tx.element_by_text("Test message").is_element_displayed():
self.errors.append("No message shown when signing!")
keycard = send_tx.sign_with_keycard_button.click()
keycard.enter_default_pin()
if not keycard.element_by_text_part('Signed message').is_element_displayed():
self.errors.append('Message was not signed')
keycard.just_fyi('Check logcat for sensitive data')
values_in_logcat = send_tx.find_values_in_logcat(pin=pin, puk=puk, password=pair_code)
if values_in_logcat:
self.sign_in.driver.fail("After signing message: %s" % values_in_logcat)
self.wallet.just_fyi("Check send 2 txs in batch")
status_test_dapp.send_two_tx_in_batch_button.scroll_to_element()
send_tx = status_test_dapp.send_two_tx_in_batch_button.click()
send_tx.sign_transaction(keycard=True)
if not send_tx.sign_with_keycard_button.is_element_displayed(10):
self.sign_in.driver.fail('Second send transaction screen did not appear!')
send_tx.sign_transaction(keycard=True)
self.wallet.just_fyi("Checking send 2 txs one after another")
status_test_dapp.send_two_tx_one_by_one_button.scroll_to_element()
send_tx = status_test_dapp.send_two_tx_one_by_one_button.click()
send_tx.sign_transaction(keycard=True)
if not send_tx.sign_with_keycard_button.is_element_displayed(20):
self.sign_in.driver.fail('Second send transaction screen did not appear!')
send_tx.sign_transaction(keycard=True)
self.wallet.just_fyi('Verify that wallet balance is updated after receiving money from faucet')
self.home.wallet_button.click()
self.wallet.wait_balance_is_changed('STT', initial_balance=self.initial_balances['STT'])
self.errors.verify_no_errors()
@marks.testrail_id(700770)
def test_keycard_wallet_recover_pairing_check_balance_after_offline_tx_history(self):
user = transaction_senders['A']
self.sign_in.toggle_airplane_mode()
self.sign_in.driver.reset()
self.sign_in.just_fyi('Keycard: recover multiaccount with pairing code ')
self.sign_in.accept_tos_checkbox.enable()
self.sign_in.get_started_button.click_until_presence_of_element(self.sign_in.access_key_button)
self.sign_in.access_key_button.click()
self.sign_in.recover_with_keycard_button.click()
keycard = self.sign_in.begin_recovery_button.click()
keycard.connect_pairing_card_button.click()
keycard.pair_code_input.set_value(pair_code)
self.sign_in.pair_to_this_device_button.click()
keycard.enter_default_pin()
self.sign_in.maybe_later_button.click_until_presence_of_element(self.sign_in.lets_go_button)
self.sign_in.lets_go_button.click_until_absense_of_element(self.sign_in.lets_go_button)
self.sign_in.home_button.wait_for_visibility_of_element(30)
self.sign_in.just_fyi("Check balance will be restored after going back online")
self.sign_in.toggle_airplane_mode()
wallet = self.home.wallet_button.click()
[wallet.wait_balance_is_changed(asset) for asset in ("ETH", "LXS")]
self.wallet.just_fyi("Checking whole tx history after backing from offline")
self.wallet.accounts_status_account.click()
address = user['address']
ropsten_txs = self.network_api.get_transactions(address)
ropsten_tokens = self.network_api.get_token_transactions(address)
expected_txs_list = get_merged_txs_list(ropsten_txs, ropsten_tokens)
transactions = self.wallet.transaction_history_button.click()
if self.wallet.element_by_translation_id("transactions-history-empty").is_element_displayed():
self.wallet.pull_to_refresh()
status_tx_number = transactions.transactions_table.get_transactions_number()
if status_tx_number < 1:
self.errors.append('No transactions found')
for n in range(status_tx_number):
transactions_details = transactions.transactions_table.transaction_by_index(n).click()
tx_hash = transactions_details.get_transaction_hash()
tx_from = transactions_details.get_sender_address()
tx_to = transactions_details.get_recipient_address()
if tx_from != expected_txs_list[tx_hash]['from']:
self.errors.append('Transactions senders do not match!')
if tx_to != expected_txs_list[tx_hash]['to']:
self.errors.append('Transactions recipients do not match!')
transactions_details.close_button.click()
self.errors.verify_no_errors()
@marks.testrail_id(5689)
def test_keycard_create_account_unlock_same_seed(self):
self.sign_in.driver.reset()
self.sign_in.just_fyi("Create keycard account and save seed phrase")
self.sign_in.accept_tos_checkbox.enable()
self.sign_in.get_started_button.click()
self.sign_in.generate_key_button.click_until_presence_of_element(self.sign_in.next_button)
self.sign_in.next_button.click_until_absense_of_element(self.sign_in.element_by_translation_id("intro-wizard-title2"))
keycard_flow = self.sign_in.keycard_storage_button.click()
keycard_flow.confirm_pin_and_proceed()
seed_phrase = keycard_flow.backup_seed_phrase()
self.sign_in.maybe_later_button.wait_for_visibility_of_element(30)
self.sign_in.maybe_later_button.click_until_presence_of_element(self.sign_in.lets_go_button)
self.sign_in.lets_go_button.click_until_absense_of_element(self.sign_in.lets_go_button)
self.sign_in.profile_button.wait_for_visibility_of_element(30)
self.sign_in.just_fyi('Check that after creating keycard account balance is 0, not ...')
wallet_1 = self.sign_in.wallet_button.click()
wallet_address = wallet_1.get_wallet_address()
wallet_1.wallet_button.double_click()
if wallet_1.status_account_total_usd_value.text != '0':
self.errors.append("Account USD value is not 0, it is %s" % wallet_1.status_account_total_usd_value.text)
public_key, default_username = self.sign_in.get_public_key_and_username(return_username=True)
profile_1 = self.sign_in.get_profile_view()
profile_1.logout()
profile_1.just_fyi('Check that can re-login with keycard account after account creation')
self.sign_in.multi_account_on_login_button.wait_for_visibility_of_element(5)
self.sign_in.multi_account_on_login_button.click()
if not keycard_flow.element_by_text_part(default_username).is_element_displayed():
self.errors.append("%s is not found on keycard login screen!" % default_username)
keycard_flow.enter_default_pin()
if not self.sign_in.home_button.is_element_displayed(10):
self.errors.append('Keycard user is not logged in')
self.sign_in.just_fyi('Unlock keycard multiaccount at attempt to restore same multiaccount from seed')
self.sign_in.profile_button.click()
profile_1.logout()
self.sign_in.access_key_button.click()
self.sign_in.enter_seed_phrase_button.click()
self.sign_in.seedphrase_input.click()
self.sign_in.seedphrase_input.set_value(seed_phrase)
self.sign_in.next_button.click()
self.sign_in.element_by_translation_id("unlock", uppercase=True).click()
keycard_flow.enter_default_pin()
device_1_home = self.sign_in.home_button.click()
device_1_home.plus_button.click()
if not device_1_home.start_new_chat_button.is_element_displayed():
self.errors.append("Can't proceed using account after it's re-recover twice.")
self.sign_in.just_fyi("Restore same multiaccount from backed up seed phrase on another device")
self.sign_in.driver.reset()
self.sign_in.recover_access(seed_phrase)
self.sign_in.just_fyi("Check username and wallet address on restored account")
wallet_2 = self.sign_in.wallet_button.click()
wallet_address_2 = wallet_2.get_wallet_address()
wallet_2.wallet_button.double_click()
if wallet_address != wallet_address_2:
self.errors.append('Wallet address on restored multiaccount is not equal to created keycard multiaccount')
public_key_2, default_username_2 = self.sign_in.get_public_key_and_username(return_username=True)
if public_key != public_key_2:
self.errors.append('Public key on restored multiaccount is not equal to created keycard multiaccount')
if default_username_2 != default_username:
self.errors.append('Username on restored multiaccount is not equal to created keycard multiaccount')
self.errors.verify_no_errors()
+3
View File
@@ -3,8 +3,11 @@ import pytest
testrail_case_id = pytest.mark.testrail_case_id
testrail_id = pytest.mark.testrail_id # atomic tests
critical = pytest.mark.critical
high = pytest.mark.high
medium = pytest.mark.medium
low = pytest.mark.low
flaky = pytest.mark.flaky
transaction = pytest.mark.transaction
upgrade = pytest.mark.upgrade
skip = pytest.mark.skip
@@ -1,436 +0,0 @@
import random
from time import sleep
import emoji
import pytest
from tests import marks
from tests.base_test_case import create_shared_drivers, MultipleSharedDeviceTestCase
from views.sign_in_view import SignInView
@pytest.mark.xdist_group(name="public_chat_medium_2")
@marks.medium
class TestPublicChatMultipleDeviceMergedMedium(MultipleSharedDeviceTestCase):
@classmethod
def setup_class(cls):
cls.drivers, cls.loop = create_shared_drivers(2)
device_1, device_2 = SignInView(cls.drivers[0]), SignInView(cls.drivers[1])
cls.home_1, cls.home_2 = device_1.create_user(), device_2.create_user()
profile_1 = cls.home_1.profile_button.click()
cls.public_key_1, cls.username_1 = profile_1.get_public_key_and_username(return_username=True)
profile_1.home_button.click()
cls.text_message = 'hello'
[home.home_button.click() for home in (cls.home_1, cls.home_2)]
cls.public_chat_name = cls.home_1.get_random_chat_name()
cls.chat_1, cls.chat_2 = cls.home_1.join_public_chat(cls.public_chat_name), cls.home_2.join_public_chat(
cls.public_chat_name)
cls.chat_1.send_message(cls.text_message)
@marks.testrail_id(6342)
def test_public_chat_timeline_different_statuses_reaction(self):
emoji_message = random.choice(list(emoji.EMOJI_UNICODE))
emoji_unicode = emoji.EMOJI_UNICODE[emoji_message]
self.home_1.just_fyi('Set status in profile')
statuses = {
'*formatted text*': 'formatted text',
'https://www.youtube.com/watch?v=JjPWmEh2KhA': 'Status Town Hall',
emoji.emojize(emoji_message): emoji_unicode,
}
timeline_1 = self.home_1.status_button.click()
for status in statuses.keys():
timeline_1.set_new_status(status)
sleep(60)
timeline_1.element_by_translation_id("enable").wait_and_click()
timeline_1.element_by_translation_id("enable-all").wait_and_click()
timeline_1.close_modal_view_from_chat_button.click()
for status in statuses:
expected_value = statuses[status]
if not timeline_1.element_by_text_part(expected_value).is_element_displayed():
self.errors.append("Expected value %s is not shown" % expected_value)
text_status = 'some text'
timeline_1.set_new_status(status=text_status, image=True)
for timestamp in ('Now', '1M', '2M'):
if not timeline_1.element_by_text(timestamp).is_element_displayed():
self.errors.append("Expected timestamp %s is not shown in timeline_1" % timestamp)
if not timeline_1.image_message_in_chat.is_element_displayed():
self.errors.append("Timeline image is not shown in timeline_1")
self.home_2.just_fyi('Check that can see user status without adding him as contact')
self.home_2.home_button.click()
chat_2 = self.home_2.add_contact(self.public_key_1, add_in_contacts=False)
chat_2.chat_options.click()
timeline_2 = chat_2.view_profile_button.click()
if not timeline_2.image_message_in_chat.is_element_displayed(40):
self.errors.append(
'Timeline image of another user is not shown when open another user profile before adding to contacts')
chat_2.chat_element_by_text(text_status).wait_for_element(30)
chat_2.element_by_translation_id("enable").scroll_and_click()
chat_2.element_by_translation_id("enable-all").wait_and_click()
chat_2.close_modal_view_from_chat_button.click()
for status in statuses:
chat_2.element_by_text_part(statuses['*formatted text*']).scroll_to_element()
expected_value = statuses[status]
if not chat_2.element_by_text_part(expected_value).is_element_displayed():
self.errors.append(
"Expected value %s is not shown in other user profile without adding to contacts" % expected_value)
self.home_2.just_fyi('Add device1 to contacts and check that status will be shown in timeline_1')
chat_2.close_button.scroll_and_click(direction='up')
chat_2.add_to_contacts.click()
timeline_2 = chat_2.status_button.click()
for status in statuses:
expected_value = statuses[status]
if not timeline_2.element_by_text_part(expected_value).is_element_displayed():
self.errors.append(
"Expected value %s is not shown in timeline_1 after adding user to contacts" % expected_value)
if not timeline_2.image_message_in_chat.is_element_displayed(40):
self.errors.append(
'Timeline image of another user is not shown when open another user profile after adding to contacts')
self.home_2.just_fyi('Checking message tag and reactions on statuses')
tag_status = '#public-chat-to-redirect-long-name'
timeline_1.set_new_status(tag_status)
public_chat_2 = self.home_2.get_chat_view()
public_chat_2.element_by_text(tag_status).wait_and_click()
public_chat_2.user_name_text.wait_for_element(30)
if not public_chat_2.user_name_text.text == tag_status:
self.errors.append('Could not redirect a user to a public chat tapping the tag message from timeline_1')
public_chat_2.back_button.click()
timeline_1.set_reaction(text_status)
status_with_reaction_1 = timeline_1.chat_element_by_text(text_status)
if status_with_reaction_1.emojis_below_message() != 1:
self.errors.append("Counter of reaction is not updated on your own status in timeline_1!")
self.home_2.home_button.double_click()
self.home_2.get_chat(self.username_1).click()
chat_2.chat_options.click()
chat_2.view_profile_button.click()
status_with_reaction_2 = chat_2.chat_element_by_text(text_status)
if status_with_reaction_2.emojis_below_message(own=False) != 1:
self.errors.append("Counter of reaction is not updated on status of another user in profile!")
self.home_1.just_fyi("Remove reaction and check it is updated for both users")
timeline_1.set_reaction(text_status)
status_with_reaction_1 = timeline_1.chat_element_by_text(text_status)
if status_with_reaction_1.emojis_below_message() != 0:
self.errors.append(
"Counter of reaction is not updated after removing reaction on your own status in timeline_1!")
status_with_reaction_2 = chat_2.chat_element_by_text(text_status)
if status_with_reaction_2.emojis_below_message(own=False) != 0:
self.errors.append(
"Counter of reaction is not updated after removing on status of another user in profile!")
self.home_1.just_fyi("Remove user from contacts and check there is no his status in timeline_1 anymore")
chat_2.remove_from_contacts.click()
chat_2.close_button.click()
chat_2.status_button.click()
if public_chat_2.chat_element_by_text(text_status).is_element_displayed(10):
self.errors.append("Statuses of removed user are still shown in profile")
self.errors.verify_no_errors()
@pytest.mark.xdist_group(name="chat_medium_2")
@marks.medium
class TestChatMultipleDevice(MultipleSharedDeviceTestCase):
@classmethod
def setup_class(cls):
cls.drivers, cls.loop = create_shared_drivers(2)
cls.device_1, cls.device_2 = SignInView(cls.drivers[0]), SignInView(cls.drivers[1])
cls.home_1, cls.home_2 = cls.device_1.create_user(enable_notifications=True), cls.device_2.create_user()
cls.public_key_1, cls.default_username_1 = cls.home_1.get_public_key_and_username(return_username=True)
cls.public_key_2, cls.default_username_2 = cls.home_2.get_public_key_and_username(return_username=True)
profile_2 = cls.home_2.profile_button.click()
profile_2.switch_network()
[home.home_button.click() for home in (cls.home_1, cls.home_2)]
cls.home_1.just_fyi("Creating 1-1 chats")
cls.chat_1 = cls.home_1.add_contact(cls.public_key_2)
cls.chat_2 = cls.home_2.add_contact(cls.public_key_1)
cls.home_2.just_fyi('Install free sticker pack and use it in 1-1 chat')
cls.chat_2.install_sticker_pack_by_name()
[home.home_button.click() for home in (cls.home_1, cls.home_2)]
cls.home_1.just_fyi("Creating group chats")
cls.initial_group_chat_name = "GroupChat before rename"
cls.new_group_chat_name = "GroupChat after rename"
cls.group_chat_1 = cls.home_1.create_group_chat(user_names_to_add=[cls.default_username_2], group_chat_name=cls.initial_group_chat_name)
cls.group_chat_2 = cls.home_2.get_chat(cls.initial_group_chat_name).click()
cls.group_chat_2.join_chat_button.click()
[home.home_button.click() for home in (cls.home_1, cls.home_2)]
cls.home_1.just_fyi("Creating public chats")
cls.public_chat_name = cls.home_1.get_random_chat_name()
cls.public_chat_1, cls.public_chat_2 = cls.home_1.join_public_chat(cls.public_chat_name), cls.home_2.join_public_chat(cls.public_chat_name)
[home.home_button.click() for home in (cls.home_1, cls.home_2)]
cls.home_1.get_chat(cls.default_username_2).click()
cls.home_2.get_chat(cls.default_username_1).click()
cls.message_1, cls.message_2, cls.message_3, cls.message_4 = "Message1", "Message2", "Message3", "Message4"
@marks.testrail_id(702066)
def test_chat_1_1_push_and_reaction_for_messages_sticker_audio_image(self):
# methods with steps to use later in loop
def navigate_to_start_state_of_both_devices():
self.chat_1.put_app_to_background()
self.device_1.open_notification_bar()
self.chat_2.get_back_to_home_view(2)
self.home_2.get_chat_from_home_view(self.default_username_1).click()
def device_2_sends_sticker():
self.chat_2.just_fyi("Sending Sticker in chat")
self.chat_2.show_stickers_button.click()
self.chat_2.sticker_icon.click()
def device_2_sends_image():
self.chat_2.just_fyi("Sending Image in chat")
self.chat_2.show_images_button.click()
self.chat_2.allow_button.click()
self.chat_2.first_image_from_gallery.click()
self.chat_2.send_message_button.click()
def device_2_sends_audio():
self.chat_2.just_fyi("Sending Audio in chat")
self.chat_2.record_audio_message(message_length_in_seconds=3)
self.chat_2.send_message_button.click()
sending_list = {
"sticker": device_2_sends_sticker,
"image": device_2_sends_image,
"audio": device_2_sends_audio,
}
for key, value in sending_list.items():
navigate_to_start_state_of_both_devices()
sending_list[key]()
if not self.device_1.element_by_text_part(key.capitalize()).is_element_displayed(10):
self.errors.append("%s not appeared in Push Notification" % key.capitalize())
self.device_1.click_system_back_button()
self.device_1.get_app_from_background()
else:
self.device_1.element_by_text_part(key.capitalize()).click()
message = self.chat_2.chat_element_by_text(key)
self.chat_1.set_reaction(key)
if message.emojis_below_message(own=False) != 1:
self.errors.append("Counter of reaction is not set on %s for message receiver!" % key)
self.chat_1.set_reaction(key)
if message.emojis_below_message(own=False) == 1:
self.errors.append("Counter of reaction is not re-set on %s for message receiver!" % key)
self.chat_2.just_fyi("Sending Emoji/Tag/Links in chat")
# TODO: add link and tag messages after #11168 is fixed(rechecked 23.11.21, valid)
navigate_to_start_state_of_both_devices()
emoji_name = random.choice(list(emoji.EMOJI_UNICODE))
emoji_unicode = emoji.EMOJI_UNICODE[emoji_name]
self.chat_2.just_fyi("Sending Emoji in chat")
self.chat_2.chat_message_input.send_keys(emoji.emojize(emoji_name))
self.chat_2.send_message_button.click()
if not self.device_1.element_by_text_part(emoji_unicode).is_element_displayed(10):
self.errors.append("Emoji not appeared in Push Notification")
self.device_1.click_system_back_button()
self.device_1.get_app_from_background()
else:
self.device_1.element_by_text_part(emoji_unicode).click()
emoji_message = self.chat_2.chat_element_by_text(emoji_unicode)
self.chat_1.set_reaction(emoji_unicode, emoji_message=True)
if emoji_message.emojis_below_message(own=False) != 1:
self.errors.append("Counter of reaction is not set on Emoji for message receiver!")
self.chat_1.set_reaction(emoji_unicode, emoji_message=True)
if emoji_message.emojis_below_message(own=False) == 1:
self.errors.append("Counter of reaction is not re-set on Emoji for message receiver!")
self.errors.verify_no_errors()
@marks.testrail_id(702069)
def test_chat_1_1_pin_messages(self):
self.home_1.just_fyi("Check that Device1 can pin own message in 1-1 chat")
self.chat_1.send_message(self.message_1)
self.chat_1.send_message(self.message_2)
self.chat_1.pin_message(self.message_1)
if not self.chat_1.chat_element_by_text(self.message_1).pinned_by_label.is_element_present():
self.drivers[0].fail("Message is not pinned!")
self.home_1.just_fyi("Check that Device2 can pin Device1 message in 1-1 chat and two pinned "
"messages are in Device1 profile")
self.chat_2.pin_message(self.message_2)
self.chat_2.chat_options.click()
self.chat_2.view_profile_button.click()
if not self.chat_2.pinned_messages_button.count == "2":
self.drivers[0].fail("Pinned message count is not 2 as expected!")
self.home_1.just_fyi("Check pinned message are visible in Pinned panel for both users")
self.chat_1.chat_options.click()
self.chat_1.view_profile_button.click()
self.chat_1.pinned_messages_button.click()
if not (self.chat_1.chat_element_by_text(self.message_1).pinned_by_label.is_element_present() and
self.chat_1.chat_element_by_text(self.message_2).pinned_by_label.is_element_present() and
self.chat_1.chat_element_by_text(self.message_1).is_element_present() and
self.chat_1.chat_element_by_text(self.message_2).is_element_present()):
self.drivers[0].fail("Something missed on Pinned messaged on Device 1!")
self.chat_2.pinned_messages_button.click()
if not (self.chat_1.chat_element_by_text(self.message_1).pinned_by_label.is_element_present() and
self.chat_2.chat_element_by_text(self.message_2).pinned_by_label.is_element_present() and
self.chat_2.chat_element_by_text(self.message_1).is_element_present() and
self.chat_2.chat_element_by_text(self.message_2).is_element_present()):
self.drivers[0].fail("Something missed on Pinned messaged on Device 2!")
self.chat_1.close_button.click()
self.home_1.just_fyi("Check that Device1 can not pin more than 3 messages and 'Unpin' dialog appears"
"messages are in Device1 profile")
self.chat_1.send_message(self.message_3)
self.chat_1.send_message(self.message_4)
self.chat_1.pin_message(self.message_3)
self.chat_1.pin_message(self.message_4)
if not self.chat_1.unpin_message_popup.is_element_present():
self.drivers[0].fail("No 'Unpin' dialog appears when pining 4th message")
self.home_1.just_fyi("Unpin one message so that another could be pinned")
self.chat_1.unpin_message_popup.message_text(self.message_1).click()
self.chat_1.unpin_message_popup.click_unpin_message_button()
if self.chat_1.unpin_message_popup.is_element_present():
self.drivers[0].fail("Unpin message pop up keep staying after Unpin button pressed")
if self.chat_1.chat_element_by_text(self.message_1).pinned_by_label.is_element_present():
self.drivers[0].fail("Message is not unpinned!")
if not self.chat_1.chat_element_by_text(self.message_4).pinned_by_label.is_element_present():
self.drivers[0].fail("Message is not pinned!")
self.home_1.just_fyi("Unpin another message and check it's unpinned for another user")
self.chat_2.close_button.click()
self.chat_2.pin_message(self.message_4, action="unpin")
self.chat_1.chat_element_by_text(self.message_4).pinned_by_label.wait_for_invisibility_of_element()
if self.chat_1.chat_element_by_text(self.message_4).pinned_by_label.is_element_present():
self.drivers[0].fail("Message_4 is not unpinned!")
@marks.testrail_id(702065)
def test_chat_public_markdown_support(self):
markdown = {
'bold text in asterics': '**',
'bold text in underscores': '__',
'italic text in asteric': '*',
'italic text in underscore': '_',
'inline code': '`',
'code blocks': '```',
'quote reply (one row)': '>',
}
for message, symbol in markdown.items():
self.home_1.just_fyi('checking that "%s" is applied (%s) in 1-1 chat' % (message, symbol))
message_to_send = symbol + message + symbol if 'quote' not in message else symbol + message
self.chat_2.send_message(message_to_send)
if not self.chat_2.chat_element_by_text(message).is_element_displayed():
self.errors.append('%s is not displayed with markdown in 1-1 chat for the sender \n' % message)
if not self.chat_1.chat_element_by_text(message).is_element_displayed():
self.errors.append('%s is not displayed with markdown in 1-1 chat for the recipient \n' % message)
[chat.home_button.double_click() for chat in (self.chat_1, self.chat_2)]
[home.get_chat('#' + self.public_chat_name).click() for home in (self.home_1, self.home_2)]
for message, symbol in markdown.items():
self.home_1.just_fyi('checking that "%s" is applied (%s) in public chat' % (message, symbol))
message_to_send = symbol + message + symbol if 'quote' not in message else symbol + message
self.public_chat_1.send_message(message_to_send)
if not self.public_chat_2.chat_element_by_text(message).is_element_displayed(30):
self.errors.append('%s is not displayed with markdown in public chat for the sender \n' % message)
if not self.public_chat_1.chat_element_by_text(message).is_element_displayed(30):
self.errors.append('%s is not displayed with markdown in public chat for the recipient \n' % message)
self.errors.verify_no_errors()
@marks.testrail_id(702098)
def test_chat_group_chat_rename(self):
[chat.home_button.double_click() for chat in [self.chat_1, self.chat_2]]
self.home_2.just_fyi('Rename chat and check system messages')
[home.get_chat(self.initial_group_chat_name).click() for home in (self.home_1, self.home_2)]
self.group_chat_1.rename_chat_via_group_info(self.new_group_chat_name)
for chat in (self.group_chat_1, self.group_chat_2):
if not chat.element_by_text(
chat.create_system_message(self.default_username_1, self.initial_group_chat_name)).is_element_displayed():
self.errors.append('Initial system message about creating chat was changed!')
if not chat.element_by_text(
chat.changed_group_name_system_message(self.default_username_1,
self.new_group_chat_name)).is_element_displayed():
self.errors.append('Message about changing chat name is not shown')
self.home_2.just_fyi('Check that you can see renamed chat')
self.group_chat_2.back_button.click()
self.home_2.get_chat(self.new_group_chat_name).wait_for_visibility_of_element(60)
self.errors.verify_no_errors()
@marks.testrail_id(702097)
def test_chat_block_and_unblock_user_from_group_chat_via_group_info(self):
[chat.home_button.double_click() for chat in [self.chat_1, self.chat_2]]
self.home_2.just_fyi('Send message and block user via Group Info')
[home.get_chat(self.new_group_chat_name).click() for home in (self.home_1, self.home_2)]
message_before_block = 'message from device2'
self.group_chat_2.send_message(message_before_block)
options_2 = self.group_chat_1.get_user_options(self.default_username_2)
options_2.view_profile_button.click()
options_2.block_contact()
self.home_1.close_button.click()
if self.group_chat_1.chat_element_by_text(message_before_block).is_element_displayed(10):
self.errors.append('User was blocked, but past message are shown')
message_after_block = 'message from device2 after block'
self.group_chat_2.send_message(message_after_block)
if self.group_chat_1.chat_element_by_text(message_after_block).is_element_displayed(10):
self.errors.append('User was blocked, but new messages still received')
self.home_1.just_fyi('Unblock user via group info and check that new messages will arrive')
options_2 = self.group_chat_1.get_user_options(self.default_username_2)
options_2.view_profile_button.click()
options_2.unblock_contact_button.click()
[options_2.close_button.click() for _ in range(2)]
message_after_unblock = 'message from device2 after unblock'
self.group_chat_2.send_message(message_after_unblock)
if not self.group_chat_1.chat_element_by_text(message_after_unblock).is_element_displayed(20):
self.errors.append('User was unblocked, but new messages are not received')
self.errors.verify_no_errors()
@marks.testrail_id(702070)
def test_chat_pin_messages_in_group_chat(self):
[chat.home_button.double_click() for chat in [self.chat_1, self.chat_2]]
self.home_1.just_fyi("Enter group chat and pin message there. It's pinned for both members.")
[home.get_chat(self.new_group_chat_name).click() for home in (self.home_1, self.home_2)]
self.group_chat_1.send_message(self.message_1)
self.group_chat_1.pin_message(self.message_1)
if not (self.group_chat_1.chat_element_by_text(self.message_1).pinned_by_label.is_element_present(30) and
self.group_chat_2.chat_element_by_text(self.message_1).pinned_by_label.is_element_present(30)):
self.errors.append("Message is not pinned in group chat!")
self.home_1.just_fyi("Check that non admin user can not unpin messages")
self.group_chat_2.chat_element_by_text(self.message_1).long_press_element()
if self.group_chat_2.element_by_translation_id("unpin").is_element_present():
self.errors.append("Unpin option is available for non-admin user")
self.home_1.just_fyi("Grant another user with admin rights and check he can unpin message now")
self.group_chat_1.chat_options.click()
group_info = self.group_chat_1.group_info.click()
options = group_info.get_username_options(self.default_username_2).click()
options.make_admin_button.click()
self.group_chat_2.click_system_back_button()
self.group_chat_2.pin_message(self.message_1, action="unpin")
if (self.group_chat_1.chat_element_by_text(self.message_1).pinned_by_label.is_element_present() and
self.group_chat_2.chat_element_by_text(self.message_1).pinned_by_label.is_element_present()):
self.errors.append("Message failed be unpinned by user who granted admin permissions!")
self.errors.verify_no_errors()

Some files were not shown because too many files have changed in this diff Show More