This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-11-17
Channels
- # aws (3)
- # beginners (81)
- # boot (155)
- # capetown (2)
- # cider (32)
- # clara (14)
- # cljs-dev (40)
- # cljsrn (12)
- # clojure (158)
- # clojure-austin (5)
- # clojure-korea (6)
- # clojure-poland (1)
- # clojure-russia (63)
- # clojure-spec (45)
- # clojure-uk (75)
- # clojurescript (109)
- # code-reviews (1)
- # core-logic (12)
- # core-matrix (1)
- # cursive (36)
- # datomic (16)
- # defnpodcast (1)
- # devcards (2)
- # editors (3)
- # euroclojure (1)
- # events (3)
- # flambo (1)
- # hoplon (19)
- # javascript (4)
- # jobs (1)
- # lein-figwheel (4)
- # leiningen (1)
- # off-topic (1)
- # om (177)
- # onyx (121)
- # pedestal (14)
- # planck (19)
- # proton (3)
- # re-frame (36)
- # reagent (21)
- # remote-jobs (1)
- # ring (4)
- # ring-swagger (6)
- # spacemacs (1)
- # specter (2)
- # test-check (4)
- # untangled (9)
- # utah-clojurians (1)
- # yada (2)
Is there a good way to do end to end testing or testing UI elements with re-frame? Is there a way to do this with a library like doo?
We're just using phantomjs and plain old js to run UI tests. Started with doo based version but it turned out very fast to be expensive.
Would very much like to have some de-facto standard way of doing this stuff in clj. Also would like to have something better than phantomjs... But that's different story š
@tom I don't do much testing yet. If you have schemas for all your subscriptions and no logic in the components like re-frame recommends, not much can go wrong there, as long as the schemas are good. I suppose testing would be a matter of dispatching tons of events and verify that the subs stay consistent with your schemas.
if you mean simulating a user doing actions in the browser I use this https://github.com/semperos/clj-webdriver
We use clj-webdriver for testing our re-frame webapp. Be aware that the project hasnāt seen much love recently. It now requires ageing Selenium dependencies that have compatibility issues with latest versions of Chrome and Firefox when running locally.
@lsnape @elahti check nightmare.js, it has a nice api and uses electron under the hood: http://www.nightmarejs.org/
I would like to have all my dispatches being dispatch-sync when Iām running tests. Trying to re-register the :dispatch
fx I get an error though saying that
> You can't call dispatch-sync within an event handler.
Does anyone else have a good way to test handlers that dispatch to other handlers? I would prefer not to use setTimeout but to do it synchonously.
@vikeri someone can correct me if i'm wrong, but i think the point of having reg-event-fx
is so that your handlers remain as pure functions and can therefore be tested individually
so you could mock the data and test the function registered to the handler, not the handler itself
@joshkh i was just reading about this the other day and, yes, that jives with my understanding
or maybe you can leverage the async-flow-fx? https://github.com/Day8/re-frame-async-flow-fx
i used it to boot my application
(defn boot-flow
[]
{:first-dispatch [:auth/fetch-anonymous-token {:root ""}]
:rules [{:when :seen?
:events [:auth/store-token]
:dispatch [:main/fetch-assets]}
{:when :seen-all-of?
:events [:main/save-summary-fields
:main/save-model]
:dispatch [:im-tables.main/run-query]}]})
Yes Iām using fx handlers, thatās why I have a :dispatch
key in the handler. I understand that there is a point in testing the handlerās function as a unit test. But I would also like to have a more āintegration testā-like behaviour when I can fire a bunch of dispatches and check that my state is where it should be when everything has finished.
then yes, maybe async-flow can work? you could watch for the last event and then check the app's state
i've asked for help in here before but this is still doing my head in... i have a standalone re-frame application which is a fancy data table. now i want to include multiple instances of the data table in a different re-frame application. so far, i understand that:
1. All of the data table's events and get registered to the global event registry (so it's really important to namespace them).
2. Any changes to the data table's app-db are changing the parent app's db because they're now the same app-db.
3. Since there will be multiple data tables they each need to know where in app-db to store their state.
so, when I construct the main data table, i can pass it a path: [data-table {:path [:tables :table-1]}]
, and when a data table fires an event it can say (dispatch [:save-some-state path {:results 123}])
and the :save-some-state
handler will update-in
db at the path provided.
but there are some really painful parts of this process.
1. My app is already written and there are about 50 events and 30 subs. Each one will have to be updated to accept a path parameter.
2. The :path
key supplied to the view constructor will have to be passed down to every single nested component that dispatches or subscribes to something.
so then i thought an interceptor might solve the problem:
(defn sandbox
"Returns an interceptor factory that shrinks the world
down to a subset of app-db. Changes are merged back into
the real db when the handler finishes at a path supplied
as the last argument in an event.
(dispatch [:some-event some-data [:my :sandboxed :location])"
[]
(re-frame.core/->interceptor
:id :sandbox
:before (fn [context]
(if-let [path (last (get-in context [:coeffects :event]))]
(update context :coeffects assoc
:old-db (get-in context [:coeffects :db])
:db (get-in context (concat [:coeffects :db] path)))
context))
:after (fn [context]
(if-let [path (last (get-in context [:coeffects :event]))]
(let [old-db (get-in context [:coeffects :old-db])
new-db (get-in context [:effects :db])]
(assoc-in context [:effects :db]
(assoc-in old-db path new-db)))
context))))
so the functions in the handlers could be left alone and the interceptor would handle the location of the update
but that still requires that a path be passed to every single event from every single dispatch, and i still have to update every subscription to accept a path (as far as i know there's no support for subscription middleware beyond piping in other subscriptions)
(also, i looked into the path
middleware but the paths are constructed at compile time and i need them to be dynamic)
I have a function which subscribes to a event and then should call another function. When I call it in a component, it is always called, when the component is rendered. How should I load it to refresh only on the own subscription?
Actually not. The menu is set after the first load, and not changed. I still use 0.7.0, as I didn't had the time to port the code to a newer one.
(defn component []
(let [menu (subscribe [:menu])]
(reagent/create-class
{:component-did-mount sender
:reagent-render (fn [] [sub-component @menu])})))