2019-09-07 12:57:22 +00:00
|
|
|
;; shadow-cljs configuration
|
2023-02-17 12:10:00 +00:00
|
|
|
{:source-paths ["src" "test/cljs"]
|
2019-09-07 12:57:22 +00:00
|
|
|
|
2023-02-17 12:10:00 +00:00
|
|
|
:dependencies [[reagent "1.0.0"]
|
|
|
|
[re-frame "0.12.0"]
|
|
|
|
[binaryage/oops "0.7.0"]
|
|
|
|
[com.andrewmcveigh/cljs-time "0.5.2"]
|
|
|
|
[status-im/timbre "4.10.0-2-status"]
|
|
|
|
[com.taoensso/encore "2.105.0"]
|
|
|
|
[hickory "0.7.1"]
|
|
|
|
[cljs-bean "1.3.0"]
|
|
|
|
[com.cognitect/transit-cljs "0.8.248"]
|
|
|
|
[mvxcvi/alphabase "1.0.0"]
|
|
|
|
[camel-snake-kebab "0.4.3"]
|
|
|
|
;; dev dependencies
|
|
|
|
[refactor-nrepl "2.5.0"]
|
|
|
|
[cider/cider-nrepl "0.25.3"]
|
|
|
|
[cider/piggieback "0.4.1"]
|
|
|
|
[re-frisk-remote "1.6.0"]
|
|
|
|
;; routing
|
|
|
|
[bidi "2.1.6"]
|
|
|
|
;; test dependencies
|
|
|
|
[day8.re-frame/test "0.1.5"]
|
|
|
|
[com.taoensso/tufte "2.1.0"]]
|
2019-09-07 12:57:22 +00:00
|
|
|
|
|
|
|
;; port and middleware for repl in development
|
2023-02-17 12:10:00 +00:00
|
|
|
:nrepl {:port 7888
|
|
|
|
:middleware [cider.piggieback/wrap-cljs-repl
|
|
|
|
refactor-nrepl.middleware/wrap-refactor]}
|
2019-09-07 12:57:22 +00:00
|
|
|
|
|
|
|
;; shadow-cljs web interface
|
2023-02-17 12:10:00 +00:00
|
|
|
:http {:port 3449
|
|
|
|
:host "0.0.0.0"}
|
2019-09-07 12:57:22 +00:00
|
|
|
|
2020-05-14 13:00:06 +00:00
|
|
|
:cache-blockers #{status-im.utils.js-resources status-im.ui.components.icons.icons}
|
2020-05-05 05:43:55 +00:00
|
|
|
|
2022-12-20 13:57:49 +00:00
|
|
|
:builds
|
|
|
|
{:mobile
|
2023-02-17 12:10:00 +00:00
|
|
|
{:target :react-native
|
2023-05-16 16:42:56 +00:00
|
|
|
;; To match the folder created by Nix build of JSBundle.
|
|
|
|
:output-dir "result"
|
2023-02-17 12:10:00 +00:00
|
|
|
:init-fn status-im2.core/init
|
2022-12-20 13:57:49 +00:00
|
|
|
;; When false, the Shadow-CLJS watcher won't automatically refresh
|
|
|
|
;; the target files (a.k.a hot reload). When false, you can manually
|
|
|
|
;; reload by calling `shadow.cljs.devtools.api/watch-compile-all!`.
|
2023-02-17 12:10:00 +00:00
|
|
|
:devtools {:autobuild #shadow/env ["SHADOW_AUTOBUILD_ENABLED" :default true :as :bool]}
|
|
|
|
:dev {:devtools {:after-load status-im2.setup.hot-reload/reload
|
|
|
|
:build-notify status-im2.setup.hot-reload/build-notify
|
Make component test helpers usable from the REPL (#15468)
This commit makes the test-helpers.component namespace loadable in the REPL,
plus other changes that allow for a reasonably enjoyable RDD (REPL-Driven
Development) workflow.
Why? I want to be able to get instant feedback when I render a component with
the RN Testing Library (RNTL), and only once I'm satisfied with my findings is
when I proceed to write/update the tests. This nearly instant feedback loop is
only feasible using the ClojureScript REPL, and I'd rather not endure long
recompilation cycles.
Note that by REPL I mean connecting to the CLJS REPL of the Shadow-CLJS :mobile
target.
Essentially, this is what this commit does:
- [x] Allow the test-helpers.component namespace to be evaluated in the REPL.
This is now possible because I changed all functions that assumed js/jest
existed with a guard clause using the CLJS macro exists?. Without the
guard clauses, evaluating the namespace explodes due to stuff like
js/jest.useFakeTimers that fail in compile time (it's a syntax sugar
macro).
- [x] Change the family of functions to get the translation by text to either
translate using i18n/label or translate with the dummy prefix tx:,
depending if the code is running inside the Jest runtime or not.
- [x] Wrap remaining RNTL query functions, except for the find-* ones, since
they don't work at all outside the Jest runtime.
- [x] All wrapped functions support the original arguments supported by RNTL.
Arguments are always converted with clj->js.
- [x] All wrapped functions can optionally take a node (ReactTestInstance) as
their first argument, otherwise the global screen object will be used.
This is very important! See the explanation on section Doesn't RNTL
recommend using the screen object?
- [x] Update Shadow-CLJS preloads, so that (in development) you can fire off the
REPL and always be ready to call component test helpers. This is critical!
What else would be possible? Just an idea, but now that we can easily render
components using the same machinery provided by RNTL in the tests, we can
roughly implement Storybook's Play function
https://storybook.js.org/docs/react/writing-stories/play-function
Lesson learned: In the REPL, you may need to call
(re-frame.core/clear-subscription-cache!), otherwise you will experience
subscriptions returning the same value if their arguments are the same. For
example, I faced this while playing with the namespace
status-im2.contexts.communities.menus.community-options.component-spec. There
are better ways to solve this particular problem in the context of tests if we
use the tooling provided by day8.re-frame.test.
Doesn't RNTL recommend using the screen object? Indeed, it is recommended to use
the screen object instead of destructuring the results of RNTL render. It's just
easier and less error prone, but this only works reliably within the Jest
runtime, since it automatically cleans up rendered state after each test. When
using the REPL this is no longer the case, and I faced some errors, like Unable
to find node on an unmounted component, where RNTL would refuse to re-render
components, even if I explicitly unmounted them or called cleanup.
The only reliable solution I found was to store the result of render (a node)
and pass it to every subsequent call. This is not a workaround, it's officially
supported, but it's a tad less convenient. You can also not pass the node
reference and it should work most of the time.
Practical examples
Workflow suggestion: write your local experiments in the same namespace as the
component spec and within the comment macro. This way, you can have the Jest
watcher running and a REPL connected to :mobile, and they won't step on each
other. For the test watcher, I usually change quo2-core-spec or
status-im2.core-spec to only require what I'm interested, otherwise Jest
consumes way too many resources.
```clojure
;; Namespace quo2.components.colors.color-picker.component-spec
(h/test "color picker color changed"
(let [selected (reagent/atom nil)]
(h/render [color-picker/view {:on-change #(reset! selected %)}])
(h/fire-event :press (get (h/get-all-by-label-text :color-picker-item) 0))
(-> (h/expect @selected)
(.toStrictEqual :blue))))
(comment
(def selected (atom nil))
(def c (h/render [color-picker/view {:on-change #(reset! selected %)}]))
(h/fire-event :press (get (h/get-all-by-label-text c :color-picker-item) 0))
;; Options are passed down converted to JS types.
(h/debug c {:message "Rendering header"})
@selected ; => :blue
)
```
```clojure
;; Namespace quo2.components.tags.--tests--.status-tags-component-spec
(h/test "renders status tag with pending type"
(render-status-tag {:status {:type :pending}
:label "Pending"
:size :small})
(-> (h/expect (h/get-all-by-label-text :status-tag-pending))
(.toBeTruthy))
(-> (h/expect (h/get-by-text "Pending"))
(.toBeTruthy)))
(comment
(def c (render-status-tag {:status {:type :pending}
:label "Pending"
:size :small}))
(h/get-all-by-label-text c :status-tag-pending))
```
```clojure
;; Namespace status-im2.contexts.communities.menus.community-options.component-spec
(h/test "joined and muted community"
(setup-subs {:communities/my-pending-request-to-join nil
:communities/community {:joined true
:muted true
:token-gated? true}})
(h/render [options/community-options-bottom-sheet {:id "test"}])
(-> (h/expect (h/get-by-translation-text :unmute-community))
(.toBeTruthy)))
(comment
(setup-subs {:communities/my-pending-request-to-join nil
:communities/community {:joined true
:muted true
:token-gated? true}})
(def c (h/render [options/community-options-bottom-sheet {:id "test"}]))
(some? (h/get-by-translation-text c :invite-people-from-contacts)) ; => true
)
```
2023-03-27 14:54:56 +00:00
|
|
|
:preloads [re-frisk-remote.preload
|
|
|
|
;; In order to use component test helpers in
|
|
|
|
;; the REPL we need to preload namespaces
|
|
|
|
;; that are not normally required by
|
|
|
|
;; production code, such as
|
|
|
|
;; @testing-library/react-native.
|
|
|
|
test-helpers.component]}
|
2023-02-17 12:10:00 +00:00
|
|
|
:closure-defines
|
2023-04-27 07:53:04 +00:00
|
|
|
{status-im2.config/POKT_TOKEN #shadow/env "POKT_TOKEN"
|
|
|
|
status-im2.config/INFURA_TOKEN #shadow/env "INFURA_TOKEN"
|
|
|
|
status-im2.config/OPENSEA_API_KEY #shadow/env "OPENSEA_API_KEY"
|
|
|
|
status-im2.config/ALCHEMY_ARBITRUM_GOERLI_TOKEN #shadow/env "ALCHEMY_ARBITRUM_GOERLI_TOKEN"
|
|
|
|
status-im2.config/ALCHEMY_OPTIMISM_GOERLI_TOKEN #shadow/env "ALCHEMY_OPTIMISM_GOERLI_TOKEN"
|
|
|
|
status-im2.config/ALCHEMY_OPTIMISM_MAINNET_TOKEN #shadow/env "ALCHEMY_OPTIMISM_MAINNET_TOKEN"
|
|
|
|
status-im2.config/ALCHEMY_ARBITRUM_MAINNET_TOKEN #shadow/env "ALCHEMY_ARBITRUM_MAINNET_TOKEN"}
|
2023-02-17 12:10:00 +00:00
|
|
|
:compiler-options {:output-feature-set :es5
|
|
|
|
:closure-defines
|
|
|
|
{re-frame.trace/trace-enabled? true}
|
|
|
|
:source-map false
|
|
|
|
:infer-externs true}
|
|
|
|
;; if you want to use a real device, set your local ip
|
|
|
|
;; in the SHADOW_HOST env variable to make sure that
|
|
|
|
;; it will use the right interface
|
|
|
|
:local-ip #shadow/env "SHADOW_HOST"}
|
|
|
|
:chunks {:fleets status-im.fleet.default-fleet/default-fleets}
|
2022-12-20 13:57:49 +00:00
|
|
|
:release
|
|
|
|
{:closure-defines
|
2023-04-27 07:53:04 +00:00
|
|
|
{status-im2.config/POKT_TOKEN #shadow/env "POKT_TOKEN"
|
|
|
|
status-im2.config/INFURA_TOKEN #shadow/env "INFURA_TOKEN"
|
|
|
|
status-im2.config/OPENSEA_API_KEY #shadow/env "OPENSEA_API_KEY"
|
|
|
|
status-im2.config/ALCHEMY_ARBITRUM_GOERLI_TOKEN #shadow/env "ALCHEMY_ARBITRUM_GOERLI_TOKEN"
|
|
|
|
status-im2.config/ALCHEMY_OPTIMISM_GOERLI_TOKEN #shadow/env "ALCHEMY_OPTIMISM_GOERLI_TOKEN"
|
|
|
|
status-im2.config/ALCHEMY_OPTIMISM_MAINNET_TOKEN #shadow/env "ALCHEMY_OPTIMISM_MAINNET_TOKEN"
|
|
|
|
status-im2.config/ALCHEMY_ARBITRUM_MAINNET_TOKEN #shadow/env "ALCHEMY_ARBITRUM_MAINNET_TOKEN"}
|
2022-12-20 13:57:49 +00:00
|
|
|
:compiler-options {:output-feature-set :es6
|
|
|
|
;;disable for android build as there
|
|
|
|
;;is an intermittent warning with deftype
|
|
|
|
:warnings-as-errors false
|
|
|
|
:infer-externs :auto
|
|
|
|
:static-fns true
|
|
|
|
:fn-invoke-direct true
|
|
|
|
:optimizations :advanced
|
|
|
|
:js-options {:js-provider :closure}}}}
|
|
|
|
;; the tests are ran with node, react-native dependencies are mocked
|
|
|
|
;; by using node --require override.js, which uses the node-library
|
|
|
|
;; produced by the target :mocks below and redefines node require
|
|
|
|
;; function to use the mocks instead of the rn libraries
|
|
|
|
:test
|
2023-02-17 12:10:00 +00:00
|
|
|
{:output-to "target/test/test.js"
|
|
|
|
:output-dir "target/test"
|
|
|
|
:optimizations :simple
|
|
|
|
:target :node-test
|
2022-12-20 13:57:49 +00:00
|
|
|
;; When running tests without a REPL you can uncomment below line to `make test-watch` a specific file
|
2023-02-09 03:18:49 +00:00
|
|
|
;; :ns-regexp "status-im2.subs.chat.messages-test$"
|
2022-12-20 13:57:49 +00:00
|
|
|
:main
|
|
|
|
status-im.test-runner/main
|
|
|
|
;; set :ui-driven to true to let shadow-cljs inject node-repl
|
|
|
|
:ui-driven
|
|
|
|
true
|
|
|
|
:closure-defines
|
2023-04-27 07:53:04 +00:00
|
|
|
{status-im2.config/POKT_TOKEN #shadow/env "POKT_TOKEN"
|
|
|
|
status-im2.config/INFURA_TOKEN #shadow/env "INFURA_TOKEN"
|
|
|
|
status-im2.config/OPENSEA_API_KEY #shadow/env "OPENSEA_API_KEY"
|
|
|
|
status-im2.config/ALCHEMY_ARBITRUM_GOERLI_TOKEN #shadow/env "ALCHEMY_ARBITRUM_GOERLI_TOKEN"
|
|
|
|
status-im2.config/ALCHEMY_OPTIMISM_GOERLI_TOKEN #shadow/env "ALCHEMY_OPTIMISM_GOERLI_TOKEN"
|
|
|
|
status-im2.config/ALCHEMY_OPTIMISM_MAINNET_TOKEN #shadow/env "ALCHEMY_OPTIMISM_MAINNET_TOKEN"
|
|
|
|
status-im2.config/ALCHEMY_ARBITRUM_MAINNET_TOKEN #shadow/env "ALCHEMY_ARBITRUM_MAINNET_TOKEN"}
|
2022-12-20 13:57:49 +00:00
|
|
|
:compiler-options
|
|
|
|
{;; needed because we override require and it
|
|
|
|
;; messes with source-map which reports callstack
|
|
|
|
;; exceeded exceptions instead of real issues
|
|
|
|
:source-map false
|
|
|
|
;; needed because we use deref in tests
|
|
|
|
:static-fns false
|
|
|
|
:optimizations :simple
|
|
|
|
:infer-externs true}}
|
2019-09-07 12:57:22 +00:00
|
|
|
|
2022-12-20 13:57:49 +00:00
|
|
|
;; mock.js-dependencies is mocking the react-native libraries
|
|
|
|
;; we build it as a node library so that it can be required by
|
|
|
|
;; override.js
|
|
|
|
:mocks
|
|
|
|
{:target :node-library
|
|
|
|
:exports {:mocks mocks.js-dependencies/mock}
|
|
|
|
:output-to "target/mocks/mocks.js"
|
|
|
|
:output-dir "target/mocks"
|
|
|
|
:compiler-options {:optimizations :simple
|
|
|
|
:source-map false}}
|
|
|
|
:component-test {:target :npm-module
|
2023-01-13 09:35:41 +00:00
|
|
|
:entries [quo2.core-spec status-im2.core-spec]
|
|
|
|
:ns-regexp "component-spec$"
|
2022-12-20 13:57:49 +00:00
|
|
|
:output-dir "component-spec"
|
|
|
|
:compiler-options {:warnings-as-errors false
|
|
|
|
:static-fns false
|
|
|
|
:infer-externs true}}}}
|