Merge pull request #117 from status-im/appium-setup

Appium setup & unit tests

Former-commit-id: ba1d5d1c4e
This commit is contained in:
Jarrad 2016-06-02 11:52:39 +02:00
commit 855dca08f5
33 changed files with 330 additions and 183 deletions

9
.gitignore vendored
View File

@ -50,3 +50,12 @@ target/
#
figwheel_server.log
.nrepl-port
# Lein
#
.lein-failures
## Doo
#
out
doo-index.html

View File

@ -10,7 +10,7 @@
(def root-el (r/as-element [reloader]))
(figwheel/watch-and-reload
:websocket-url "ws://10.0.3.2:3449/figwheel-ws"
:websocket-url "ws://localhost:3449/figwheel-ws"
:heads-up-display false
:jsload-callback #(swap! cnt inc))

View File

@ -8,7 +8,7 @@
[reagent "0.5.1" :exclusions [cljsjs/react]]
[re-frame "0.6.0"]
[prismatic/schema "1.0.4"]
^{:voom {:repo "https://github.com/status-im/status-lib.git"
^{:voom {:repo "git@github.com:status-im/status-lib.git"
:branch "master"}}
[status-im/protocol "0.1.1-20160525_083359-g53ab2c2"]
[natal-shell "0.1.6"]
@ -20,9 +20,12 @@
["do" "clean"
["with-profile" "prod" "cljsbuild" "once" "ios"]
["with-profile" "prod" "cljsbuild" "once" "android"]]}
:test-paths ["test/clj"]
:figwheel {:nrepl-port 7888}
:profiles {:dev {:dependencies [[figwheel-sidecar "0.5.0-2"]
[com.cemerick/piggieback "0.2.1"]]
[com.cemerick/piggieback "0.2.1"]
[io.appium/java-client "3.4.1"]]
:plugins [[lein-doo "0.1.6"]]
:source-paths ["src" "env/dev"]
:cljsbuild {:builds {:ios {:source-paths ["src" "env/dev"]
:figwheel true
@ -35,7 +38,13 @@
:compiler {:output-to "target/android/not-used.js"
:main "env.android.main"
:output-dir "target/android"
:optimizations :none}}}}
:optimizations :none}}
:test {:source-paths ["src" "test/cljs"]
:compiler
{:main status-im.test.runner
:output-to "target/test/test.js"
:optimizations :none
:target :nodejs}}}}
:repl-options {:nrepl-middleware [cemerick.piggieback/wrap-cljs-repl]}}
:prod {:cljsbuild {:builds {:ios {:source-paths ["src" "env/prod"]
:compiler {:output-to "index.ios.js"
@ -46,5 +55,4 @@
:compiler {:output-to "index.android.js"
:main "env.android.main"
:output-dir "target/android"
:optimizations :simple}}}}
}})
:optimizations :simple}}}}}})

View File

@ -17,11 +17,13 @@ function tab () {
fi
osascript &>/dev/null <<EOF
tell application "iTerm"
tell current terminal
launch session "Default Session"
tell the last session
write text "cd \"$cdto\"$cmd"
tell application "iTerm2"
tell current window
set newTab to (create tab with default profile)
tell newTab
tell current session
write text "cd \"$cdto\"$cmd"
end tell
end tell
end tell
end tell
@ -59,3 +61,10 @@ sleep 10s
adb reverse tcp:8081 tcp:8081 && adb reverse tcp:3449 tcp:3449
react-native run-android
if [ ! -z $2 ]
then
tab "appium"
lein test
lein doo node test once
fi

View File

@ -1 +1,4 @@
(ns cljsjs.react)
(ns cljsjs.react)
(when (exists? js/window)
(set! js/window.React (js/require "react-native")))

View File

@ -38,11 +38,13 @@
:onChangeText set-input-message
:onSubmitEditing (fn []
(when (valid? message validator)
(send-command)))}
(send-command)))
:accessibility-label :command-input}
input-options)
message]
(if (valid? message validator)
[touchable-highlight {:on-press send-command}
[touchable-highlight {:on-press send-command
:accessibility-label :stage-command}
[view st/send-container [icon :send st/send-icon]]]
[touchable-highlight {:on-press cancel-command-input}
[view st/cancel-container

View File

@ -72,13 +72,18 @@
(defn set-chat-command [msg-id command]
(dispatch [:set-response-chat-command msg-id (:command command)]))
(defn label [{:keys [command]}]
(->> (name command)
(str "request-")))
(defn message-content-command-request
[{:keys [msg-id content from incoming-group]}]
(let [commands-atom (subscribe [:get-commands])]
(fn [{:keys [msg-id content from incoming-group]}]
(let [commands @commands-atom
{:keys [command content]} (parse-command-request commands content)]
[touchable-highlight {:onPress #(set-chat-command msg-id command)}
[touchable-highlight {:onPress #(set-chat-command msg-id command)
:accessibility-label (label command)}
[view st/comand-request-view
[view st/command-request-message-view
(when incoming-group

View File

@ -1,9 +1,9 @@
(ns status-im.chat.views.plain-input
(:require [re-frame.core :refer [subscribe dispatch]]
[status-im.components.react :refer [view
icon
touchable-highlight
text-input]]
icon
touchable-highlight
text-input]]
[status-im.chat.views.suggestions :refer [suggestions-view]]
[status-im.chat.styles.plain-input :as st]))
@ -39,15 +39,16 @@
(if @typing-command?
[icon :close-gray st/close-icon]
[icon :list st/list-icon])]]
[text-input {:style st/message-input
:autoFocus (pos? (count @staged-commands-atom))
:onChangeText set-input-message
:onSubmitEditing #(try-send @chat @staged-commands-atom
input-message)}
[text-input {:style st/message-input
:autoFocus (pos? (count @staged-commands-atom))
:onChangeText set-input-message
:onSubmitEditing #(try-send @chat @staged-commands-atom
input-message)}
input-message]
;; TODO emoticons: not implemented
[icon :smile st/smile-icon]
(when (message-valid? @staged-commands-atom input-message)
[touchable-highlight {:on-press #(send @chat input-message)}
[touchable-highlight {:on-press #(send @chat input-message)
:accessibility-label :send-message}
[view st/send-container
[icon :send st/send-icon]]])]]))))

View File

@ -1,7 +1,7 @@
(ns status-im.components.action-button
(:require [reagent.core :as r]))
(set! js/window.ActionButton (js/require "react-native-action-button"))
(def class (js/require "react-native-action-button"))
(def action-button (r/adapt-react-class (.-default js/ActionButton)))
(def action-button-item (r/adapt-react-class (.. js/ActionButton -default -Item)))
(def action-button (r/adapt-react-class (.-default class)))
(def action-button-item (r/adapt-react-class (.. class -default -Item)))

View File

@ -5,11 +5,12 @@
touchable-without-feedback
text]]
[status-im.components.carousel.styles :as st]
[status-im.utils.logging :as log]))
[status-im.utils.logging :as log]
[status-im.components.react :as r]))
(defn window-page-width []
(.-width (.get (.. js/React -Dimensions) "window")))
(.-width (.get (.. r/react -Dimensions) "window")))
(def defaults {:gap 10
:sneak 10

View File

@ -2,14 +2,14 @@
(:require [clojure.string :as s]
[re-frame.core :refer [subscribe dispatch dispatch-sync]]
[reagent.core :as r]
[status-im.components.react :refer [android?
view
text
image
navigator
toolbar-android
drawer-layout-android
touchable-opacity]]
[status-im.components.react :refer [react
view
text
image
navigator
toolbar-android
drawer-layout-android
touchable-opacity]]
[status-im.resources :as res]
[status-im.components.drawer.styles :as st]
[status-im.i18n :refer [label]]))
@ -29,7 +29,7 @@
:style st/user-photo}])
(defn menu-item [{:keys [name handler]}]
[touchable-opacity {:style st/menu-item-touchable
[touchable-opacity {:style st/menu-item-touchable
:onPress (fn []
(close-drawer)
(handler))}
@ -40,40 +40,40 @@
(let [username (subscribe [:get :username])]
(fn []
[view st/drawer-menu
[view st/user-photo-container
[user-photo {}]]
[view st/name-container
[text {:style st/name-text}
@username]]
[view st/menu-items-container
[menu-item {:name (label :t/profile)
:handler #(dispatch [:navigate-to :my-profile])}]
[menu-item {:name (label :t/settings)
:handler (fn []
;; TODO not implemented
)}]
[menu-item {:name (label :t/discovery)
:handler #(dispatch [:navigate-to :discovery])}]
[menu-item {:name (label :t/contacts)
:handler #(dispatch [:show-contacts navigator])}]
[menu-item {:name (label :t/invite-friends)
:handler (fn []
;; TODO not implemented
)}]
[menu-item {:name (label :t/faq)
:handler (fn [])}]]
[view st/switch-users-container
[touchable-opacity {:onPress (fn []
(close-drawer)
;; TODO not implemented
)}
[text {:style st/switch-users-text}
(label :t/switch-users)]]]])))
[view st/user-photo-container
[user-photo {}]]
[view st/name-container
[text {:style st/name-text}
@username]]
[view st/menu-items-container
[menu-item {:name (label :t/profile)
:handler #(dispatch [:navigate-to :my-profile])}]
[menu-item {:name (label :t/settings)
:handler (fn []
;; TODO not implemented
)}]
[menu-item {:name (label :t/discovery)
:handler #(dispatch [:navigate-to :discovery])}]
[menu-item {:name (label :t/contacts)
:handler #(dispatch [:show-contacts navigator])}]
[menu-item {:name (label :t/invite-friends)
:handler (fn []
;; TODO not implemented
)}]
[menu-item {:name (label :t/faq)
:handler (fn [])}]]
[view st/switch-users-container
[touchable-opacity {:onPress (fn []
(close-drawer)
;; TODO not implemented
)}
[text {:style st/switch-users-text}
(label :t/switch-users)]]]])))
(defn drawer-view [items]
[drawer-layout-android {:drawerWidth 260
:drawerPosition js/React.DrawerLayoutAndroid.positions.Left
:render-navigation-view #(r/as-element [drawer-menu])
:ref (fn [drawer]
(reset! drawer-atom drawer))}
:ref (fn [drawer]
(reset! drawer-atom drawer))}
items])

View File

@ -1,6 +1,4 @@
(ns status-im.components.icons.ionicons
(:require [reagent.core :as r]))
(set! js/window.Ionicons (js/require "react-native-vector-icons/Ionicons"))
(def icon (r/adapt-react-class js/Ionicons))
(def icon (r/adapt-react-class (js/require "react-native-vector-icons/Ionicons")))

View File

@ -1,8 +1,8 @@
(ns status-im.components.invertible-scroll-view)
(ns status-im.components.invertible-scroll-view
(:require [reagent.core :as r]))
(set! js/window.InvertibleScrollView (js/require "react-native-invertible-scroll-view"))
(def class (js/require "react-native-invertible-scroll-view"))
(defn invertible-scroll-view [props]
(js/React.createElement js/InvertibleScrollView
(clj->js (merge {:inverted true} props))))
(r/create-element class (clj->js (merge {:inverted true} props))))

View File

@ -1,7 +1,5 @@
(ns status-im.components.item-checkbox
(:require [reagent.core :as r]))
(set! js/window.ItemCheckbox (js/require "react-native-circle-checkbox"))
(def item-checkbox (r/adapt-react-class js/ItemCheckbox))
(def item-checkbox (r/adapt-react-class (js/require "react-native-circle-checkbox")))

View File

@ -1,26 +1,36 @@
(ns status-im.components.react
(:require [reagent.core :as r]
[status-im.components.styles :as st]))
[status-im.components.styles :as st]
[status-im.utils.utils :as u]))
(set! js/window.React (js/require "react-native"))
(def react (u/require "react-native"))
(def app-registry (.-AppRegistry js/React))
(def navigator (r/adapt-react-class (.-Navigator js/React)))
(def text (r/adapt-react-class (.-Text js/React)))
(def view (r/adapt-react-class (.-View js/React)))
(def image (r/adapt-react-class (.-Image js/React)))
(def touchable-highlight-class (r/adapt-react-class (.-TouchableHighlight js/React)))
(defn get-react-property [name]
(aget react name))
(defn adapt-class [class]
(when class (r/adapt-react-class class)))
(defn get-class [name]
(adapt-class (get-react-property name)))
(def app-registry (get-react-property "AppRegistry"))
(def navigator (get-class "Navigator"))
(def text (get-class "Text"))
(def view (get-class "View"))
(def image (get-class "Image"))
(def touchable-highlight-class (get-class "TouchableHighlight"))
(defn touchable-highlight [props content]
[touchable-highlight-class
(merge {:underlay-color :transparent} props)
content])
(def toolbar-android (r/adapt-react-class (.-ToolbarAndroid js/React)))
(def list-view-class (r/adapt-react-class (.-ListView js/React)))
(def toolbar-android (get-class "ToolbarAndroid"))
(def list-view-class (get-class "ListView"))
(defn list-view [props]
[list-view-class (merge {:enableEmptySections true} props)])
(def scroll-view (r/adapt-react-class (.-ScrollView js/React)))
(def touchable-without-feedback (r/adapt-react-class (.-TouchableWithoutFeedback js/React)))
(def text-input-class (r/adapt-react-class (.-TextInput js/React)))
(def scroll-view (get-class "ScrollView"))
(def touchable-without-feedback (get-class "TouchableWithoutFeedback"))
(def text-input-class (get-class "TextInput"))
(defn text-input [props text]
[text-input-class (merge
{:underlineColorAndroid :transparent
@ -28,11 +38,13 @@
:placeholder "Type"}
props)
text])
(def drawer-layout-android (r/adapt-react-class (.-DrawerLayoutAndroid js/React)))
(def touchable-opacity (r/adapt-react-class (.-TouchableOpacity js/React)))
(def modal (r/adapt-react-class (.-Modal js/React)))
(def picker (r/adapt-react-class (.-Picker js/React)))
(def picker-item (r/adapt-react-class (.-Item (.-Picker js/React))))
(def drawer-layout-android (get-class "DrawerLayoutAndroid"))
(def touchable-opacity (get-class "TouchableOpacity"))
(def modal (get-class "Modal"))
(def picker (get-class "Picker"))
(def picker-item
(when-let [picker (get-react-property "Picker")]
(adapt-class (.-Item picker))))
(defn icon
@ -41,20 +53,18 @@
[image {:source {:uri (keyword (str "icon_" (name n)))}
:style style}]))
;(def react-linear-gradient (.-default (js/require "react-native-linear-gradient")))
;(def linear-gradient (r/adapt-react-class react-linear-gradient))
(set! js/window.LinearGradient (js/require "react-native-linear-gradient"))
(def linear-gradient-class (u/require "react-native-linear-gradient"))
(defn linear-gradient [props]
(js/React.createElement js/LinearGradient
(clj->js (merge {:inverted true} props))))
(r/create-element linear-gradient-class
(clj->js (merge {:inverted true} props))))
(def platform (.. js/React -Platform -OS))
(def platform
(when-let [pl (.-Platform react)] (.-OS pl)))
(def android? (= platform "android"))
(defn list-item [component]
(r/as-element component))
(def dismiss-keyboard! (js/require "dismissKeyboard"))
(def dismiss-keyboard! (u/require "dismissKeyboard"))

View File

@ -1,9 +0,0 @@
(ns status-im.components.realm
(:require [reagent.core :as r]))
(set! js/window.RealmReactNative (js/require "realm/react-native"))
(def list-view-class (r/adapt-react-class (.-ListView js/RealmReactNative)))
(defn list-view [props]
[list-view-class (merge {:enableEmptySections true} props)])

View File

@ -12,9 +12,7 @@
color-purple
text1-color
text2-color
toolbar-background1]]
[status-im.components.realm :refer [list-view]]
[reagent.core :as r]))
toolbar-background1]]))
(defn toolbar [{:keys [title nav-action hide-nav? action custom-action
background-color custom-content style]}]

View File

@ -5,7 +5,8 @@
[clojure.string :as s]
[status-im.utils.utils :refer [http-post]]
[status-im.utils.phone-number :refer [format-phone-number]]
[status-im.utils.handlers :as u]))
[status-im.utils.handlers :as u]
[status-im.utils.utils :refer [require]]))
(defn save-contact
[_ [_ contact]]
@ -26,7 +27,7 @@
(register-handler :load-contacts load-contacts!)
;; TODO see https://github.com/rt2zz/react-native-contacts/issues/45
(def react-native-contacts (js/require "react-native-contacts"))
(def react-native-contacts (require "react-native-contacts"))
(defn contact-name [contact]
(->> contact

View File

@ -2,16 +2,16 @@
(:require-macros [status-im.utils.views :refer [defview]])
(:require
[re-frame.core :refer [subscribe]]
[status-im.utils.logging :as log]
[status-im.components.react :refer [android?
text]]
[status-im.components.carousel.carousel :refer [carousel]]
[status-im.discovery.styles :as st]
[status-im.discovery.views.popular-list :refer [discovery-popular-list]]
[status-im.i18n :refer [label]]))
[status-im.i18n :refer [label]]
[status-im.components.react :as r]))
(defn page-width []
(.-width (.get (.. js/React -Dimensions) "window")))
(.-width (.get (.. r/react -Dimensions) "window")))
(defview popular []
[popular-tags [:get-popular-tags 3]]

View File

@ -35,15 +35,19 @@
;; -- Common --------------------------------------------------------------
(defn set-el [db [_ k v]]
(assoc db k v))
(register-handler :set
(debug
(fn [db [_ k v]]
(assoc db k v))))
debug
set-el)
(defn set-in [db [_ path v]]
(assoc-in db path v))
(register-handler :set-in
(debug
(fn [db [_ path v]]
(assoc-in db path v))))
debug
set-in)
(register-handler :initialize-db
(fn [_ _]

View File

@ -1,26 +1,21 @@
(ns status-im.i18n
(:require
[status-im.translations.en :as en]))
[status-im.translations.en :as en]
[status-im.utils.utils :as u]))
(set! js/window.I18n (js/require "react-native-i18n"))
(set! (.-fallbacks js/I18n) true)
(set! (.-defaultSeparator js/I18n) "/")
(def i18n (u/require "react-native-i18n"))
(set! (.-fallbacks i18n) true)
(set! (.-defaultSeparator i18n) "/")
(set! (.-translations js.I18n) (clj->js {:en en/translations}))
(set! (.-translations i18n) (clj->js {:en en/translations}))
(defn label [path & options]
(.t js/I18n (name path) (clj->js options)))
(if (exists? i18n.t)
(.t i18n (name path) (clj->js options))
(name path)))
(defn label-pluralize [count path & options]
(.p js/I18n count (name path) (clj->js options)))
(if (exists? i18n.t)
(.p i18n count (name path) (clj->js options))
(name path)))
(comment
(defn deep-merge [& maps]
(if (every? map? maps)
(apply merge-with deep-merge maps)
(last maps)))
(defn add-translations [new-translations]
(let [translations (.-translations js/I18n)]
(set! (.-translations js/I18n) (clj->js (deep-merge (js->clj translations) new-translations)))))
)

View File

@ -2,11 +2,10 @@
(:require [cljs.reader :refer [read-string]]
[status-im.components.styles :refer [default-chat-color]]
[status-im.utils.logging :as log]
[status-im.utils.types :refer [to-string]])
[status-im.utils.types :refer [to-string]]
[status-im.utils.utils :as u])
(:refer-clojure :exclude [exists?]))
(set! js/window.Realm (js/require "realm"))
(def opts {:schema [{:name :contacts
:primaryKey :whisper-identity
:properties {:phone-number {:type "string"
@ -70,7 +69,10 @@
:objectType "tag"}
:last-updated "date"}}]})
(def realm (js/Realm. (clj->js opts)))
(def realm-class (u/require "realm"))
(def realm (when (cljs.core/exists? js/window)
(realm-class. (clj->js opts))))
(def schema-by-name (->> (:schema opts)
(mapv (fn [{:keys [name] :as schema}]

View File

@ -2,14 +2,14 @@
(:require-macros [status-im.utils.views :refer [defview]])
(:require [re-frame.core :refer [subscribe dispatch]]
[status-im.components.react :refer [view
text
image
icon
scroll-view
touchable-highlight
touchable-opacity]]
text
image
icon
scroll-view
touchable-highlight
touchable-opacity]]
[status-im.components.chat-icon.screen :refer [profile-icon
my-profile-icon]]
my-profile-icon]]
[status-im.profile.styles :as st]
[status-im.i18n :refer [label]]))
@ -60,11 +60,11 @@
[text {:style st/report-user-text} (label :t/report-user)]]]]])
(defview my-profile []
[username [:get :username]
photo-path [:get :photo-path]
[username [:get :username]
photo-path [:get :photo-path]
phone-number [:get :phone-number]
email [:get :email]
status [:get :status]]
email [:get :email]
status [:get :status]]
[scroll-view {:style st/profile}
[touchable-highlight {:style st/back-btn-touchable
:on-press #(dispatch [:navigate-back])}

View File

@ -1,9 +1,10 @@
(ns status-im.utils.crypt
(:require [goog.crypt :refer [byteArrayToHex]]
[clojure.string :as s])
[clojure.string :as s]
[status-im.utils.utils :as u])
(:import goog.crypt.Sha256))
(set! js/window.RnRandomBytes (js/require "react-native-randombytes"))
(def random-bytes (u/require "react-native-randombytes"))
(def sha-256 (Sha256.))
@ -19,7 +20,7 @@
(byteArrayToHex (.digest sha-256)))
(defn gen-random-bytes [length cb]
(.randomBytes js/window.RnRandomBytes length (fn [& [err buf]]
(if err
(cb {:error err})
(cb {:buffer buf})))))
#_(.randomBytes random-bytes length (fn [& [err buf]]
(if err
(cb {:error err})
(cb {:buffer buf})))))

View File

@ -1,6 +1,5 @@
(ns status-im.utils.listview
(:require-macros [natal-shell.data-source :refer [data-source]])
(:require [status-im.components.realm]))
(:require-macros [natal-shell.data-source :refer [data-source]]))
(defn clone-with-rows [ds rows]
(.cloneWithRows ds (reduce (fn [ac el] (.push ac el) ac)

View File

@ -1,16 +1,17 @@
(ns status-im.utils.phone-number)
(ns status-im.utils.phone-number
(:require [status-im.utils.utils :as u]))
(def i18n (js/require "react-native-i18n"))
(def locale (.-locale i18n))
(def i18n (u/require "react-native-i18n"))
(def locale (or (.-locale i18n) "___en"))
(def country-code (subs locale 3 5))
(set! js/PhoneNumber (js/require "awesome-phonenumber"))
(def awesome-phonenumber (u/require "awesome-phonenumber"))
;; todo check wrong numbers, .getNumber returns empty string
(defn format-phone-number [number]
(str (.getNumber (js/PhoneNumber. number country-code "international"))))
(str (.getNumber (awesome-phonenumber. number country-code "international"))))
(defn valid-mobile-number? [number]
(when (string? number)
(let [number-obj (js/PhoneNumber. number country-code "international")]
(let [number-obj (awesome-phonenumber. number country-code "international")]
(and (.isValid number-obj)
(.isMobile number-obj)))))

View File

@ -1,7 +1,8 @@
(ns status-im.utils.sms-listener
(:require [status-im.components.react :refer [android?]]))
(:require [status-im.components.react :refer [android?]]
[status-im.utils.utils :as u]))
(def sms-listener (.-default (js/require "react-native-android-sms-listener")))
(def sms-listener (.-default (u/require "react-native-android-sms-listener")))
;; Only android is supported!

View File

@ -5,6 +5,11 @@
[natal-shell.toast-android :as toast])
(:require [status-im.constants :as const]))
(defn require [module]
(if (exists? js/window)
(js/require module)
#js {}))
(defn log [obj]
(.log js/console obj))

View File

@ -0,0 +1,86 @@
(ns status-im.appium
(:require [clojure.java.io :as io]
[clojure.test :refer :all])
(:import (org.openqa.selenium.remote DesiredCapabilities)
(org.openqa.selenium By)
(io.appium.java_client.android AndroidDriver)
(java.net URL)
(java.util.concurrent TimeUnit)))
(defn init []
(let [dir (io/file (str (System/getProperty "user.dir")
"/android/app/build/outputs/apk"))
app (io/file dir "app-debug.apk")
capabilities (doto (DesiredCapabilities.)
(.setCapability "deviceName" "device")
(.setCapability "platformVersion" "6.0.0")
(.setCapability "app" (.getAbsolutePath app))
(.setCapability "appPackage" "com.statusim")
(.setCapability "appActivity" ".MainActivity"))
driver (AndroidDriver. (URL. "http://127.0.0.1:4723/wd/hub") capabilities)]
(-> driver
.manage
.timeouts
(.implicitlyWait 25 TimeUnit/SECONDS))
driver))
(defn by-xpath [driver xpath]
(.findElement driver (By/xpath xpath)))
(defn elements-by-xpath [driver xpath]
(.findElements driver (By/xpath xpath)))
(defn by-id [driver id]
(.findElementByAccessibilityId driver (name id)))
(defn get-element [driver id]
(if (keyword? id)
(by-id driver id)
(by-xpath driver id)))
(defn click [driver id]
(.click (get-element driver id)))
(defn write [driver input-xpath text]
(.sendKeys (get-element driver input-xpath) (into-array [text])))
(defn get-text [driver xpath]
(.getText (by-xpath driver xpath)))
(defn xpath-by-text [text]
(str ".//*[@text='" text "']"))
(defn contains-text [driver text]
(is (= 1 (->> (xpath-by-text text)
(elements-by-xpath driver)
(.size)))))
(defn quit [driver]
(.quit driver))
(defmacro appium-test
"Defines test which will create new appium session and will pass that
session as first argument to each command inside it's body. After execution
of all commands session will be closed.
For instance,
(appium-test my-test
(click :button)
(write :input \"oops\"))
will be expanded to
(deftest my-test
(let [session (init)]
(click session :button)
(write session :input \"oops\")
(quit session)))"
[name & body]
(let [sym (gensym)]
`(deftest ~name
(let [~sym (init)]
~@(for [[f & rest] body]
`(~f ~sym ~@rest))
(quit ~sym)))))

View File

@ -0,0 +1,15 @@
(ns status-im.console
(:require [clojure.test :refer :all]
[status-im.appium :refer :all]))
(def message-text
(str "Your phone number is also required to use the app. Type"
" the exclamation mark or hit the icon to open the command "
"list and choose the !phone command"))
(appium-test console-test
(click :request-keypair-password)
(write :command-input "123")
(click :stage-command)
(click :send-message)
(contains-text message-text))

View File

@ -0,0 +1,6 @@
(ns status-im.test.handlers
(:require [cljs.test :refer-macros [deftest is]]
[status-im.handlers :as h]))
(deftest test-set-val
(is (= {:key :val} (h/set-el {} [nil :key :val]))))

View File

@ -0,0 +1,5 @@
(ns status-im.test.runner
(:require [doo.runner :refer-macros [doo-tests]]
[status-im.test.handlers]))
(doo-tests 'status-im.test.handlers)

View File

@ -1,7 +0,0 @@
(ns status-im.core-test
(:require [clojure.test :refer :all]
[status-im.core :refer :all]))
(deftest a-test
(testing "FIXME, I fail."
(is (= 0 1))))