This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-01-11
Channels
- # admin-announcements (3)
- # beginners (51)
- # boot (14)
- # cider (55)
- # cljsrn (5)
- # clojure (105)
- # clojure-austin (2)
- # clojure-brasil (3)
- # clojure-dusseldorf (2)
- # clojure-greece (5)
- # clojure-italy (1)
- # clojure-mexico (1)
- # clojure-russia (74)
- # clojure-spec (66)
- # clojure-uk (22)
- # clojurescript (124)
- # cursive (10)
- # datomic (79)
- # events (2)
- # immutant (3)
- # jobs (4)
- # klipse (38)
- # leiningen (2)
- # luminus (1)
- # off-topic (25)
- # om (48)
- # om-next (36)
- # on (1)
- # onyx (19)
- # overtone (3)
- # pedestal (2)
- # proton (3)
- # re-frame (178)
- # reagent (49)
- # ring-swagger (1)
- # spacemacs (10)
- # specter (29)
- # testing (5)
- # untangled (6)
- # yada (65)
Am I misunderstanding the cljs-ajax API? When I use (ajax/json-response-format {:keywords? true})
I am expecting the returned body to be parsed as JSON and returned as a Clojurescript map. What I'm seeing is a JS object that appears to be some kind of string (`#object[String "function String() { [native code] }"]`). Am I just completely misunderstanding what's supposed to happen?
@sandbags I have a wrapper for my calls that look like this:
(defn GET
[path opts]
(let [opts (assoc opts
:format (ajax/json-request-format)
:response-format (ajax/json-response-format {:keywords? true}))]
(ajax/GET path opts)))
And i get the desired effectI'm using the re-frame-http-fx extension with :response-format (ajax/json-response-format {:keywords? true})
@gadfly361 but, presumably, the issue here is the same ... by doing that do you get the (:body response)
automatically decoded into a CLJS map?
yeah, the response
itself should be decoded into a cljs map, dont think you need to call :body
I'm not sure if I am just expecting something that isn't meant to be happening and I need to decode the string response into JSON myself
"I'm not sure if I am just expecting something that isn't meant to be happening and I need to decode the string response into JSON myself" I think your expectations are fine
okay so it's just a regular JS string (I hadn't realised they all type
d as function String() { [native code] }
)
btw, is it ok to do re-frame related job postings here? 🙂
Well I'm baffled... I can't see why the json-read
call isn't returning a CLJS object
What would be a good way to periodically dispatch the same event? I’m looking at timer example (https://github.com/Day8/re-frame/blob/master/examples/simple/src/simple/core.cljs#L18) and setInterval
is just called, I want to conditionally setInterval
and clearIntervals
Or, less abstract question: what is a good way to implement polling of REST API via GET requests? I’m looking at https://github.com/Day8/re-frame-http-fx/blob/master/src/day8/re_frame/http_fx.cljs and don’t get where is the good place to sneak js/setInterval
not sure what more you're looking for other than polling an endpoint. set interval is definitely the most direct way to do that. any library you import to do it for you is just going to be doing a setInterval for you.
i missed your comment between the links... a place to sneak the setInterval? does it need to be running all the time? set it in your init, or defonce it in your core ns.
if you want to start it at only a specific time, (like when another event happens) then register an effects handler. https://github.com/Day8/re-frame/blob/master/docs/Effects.md
if you want to cancel it later (in response to another event) store the int returned by setInterval in your app-db so you can call clearInterval on it
I understand how manually to do (assoc db :interval-id (js/setInterval #(re-frame/dispatch [:polling-event])))
inside reg-event-db
, what I’m looking for is something that will do {:dispatch-polling [:event]}
in reg-event-fx
yeah thats the link i posted. register your own effect. e.g. replace the keyword :butterfly in the link with something like :start-interval and make another one for :stop-interval and in the effect handlers start and stop the interval.
the built-in effects in re-frame are :db, meant for updating app-db. :dispatch, meant for triggering events
you need your own effect which means what you want it to mean. in this case start/stopping intervals
(there are other built-in re-frame effects, those are just the first two that come to mind)
would it be possible to build an interceptor that “wraps” any given event into setInterval?
you can make interceptors that do anything, but they're only meant to modify the coeffects (inputs) and effects. i'm not immediately understanding the connection between them and what you're wanting. https://github.com/Day8/re-frame/blob/master/docs/Interceptors.md
@dragoncube I, for one, have no problem with the odd jobs posting in here
Having said that, there is a #jobs channel for that, I think
@kishanov if you want to turn on and off periodic events, then perhaps something like this:
(reg-event-fx
:something
(fn [cofx event]
;; turn on an interval
{:interval {:action :turn-on ;; turn on or off
:id 123 ;; what is the id of this interval
:frequency 1000 ;; every how many milli secs
:event [:do-poll 42]}})) ;; what event to dispatch
And also:
(reg-event-fx
:something-else
(fn [cofx event]
;; turn off an interval we previously created (using the id we previously supplied)
{:interval {:action :turn-off
:id 123}}}))
So that's how you'd turn on and off intervals ... then all you have to do is write the effect handler for :interval
Thanks, @mikethompson
(reg-fx
:interval
(let [live-intervals (atom {})]
(fn [{:keys [action id frequency event]}]
(if (= action :turn-on)
(swap! live-intervals
assoc id (js/setInterval #(dispatch event) frequency)))
(do
(js/clearInterval (get live-intervals id))
(swap! live-intervals disassoc id))))
untested and there's no error checking
If we have a lot of data coming from an external system is there any way to manage the app-db, expire items etc ?
Good news everyone! My re-learn library is now ready for use: https://github.com/oliyh/re-learn There is a write up of the rationale at https://juxt.pro/blog/posts/re-learn.html re-learn is built using re-frame and reagent and will integrate nicely with your applications to educate your users about all your cool features and updates
Here's a short demo: https://raw.githubusercontent.com/oliyh/re-learn/master/documentation/re-learn.gif
@danielcompton is there an obvious smoking gun as to why my :http-xhrio request might be returning a JS string rather than a CLJS map?
I added the :raw false
as a kind of desperation move in case somehow the wrong code path was being taken
as far as I can see the response is coming back as JSON data with Content-Type: application/json;charset=UTF-8
but I'm getting a string back in the (:body response)
When I manually try (js->clj (goog-json/parse text) :keywordize-keys true)
on the text being returned from my query I get what I expect
Anyone have any advice about patching in a replacement version of a library function?
Okay so by instrumenting json-read
I can see that the final result looks right and is a cljs.core/PersistentArrayMap
yet by the time it gets to my :on-success
handler function either the result of the json-read
has been ignored in favour of the raw response, or it has been mangled into a JS string
Okay well I have been banging my head against this problem (and the tooling to try and debug it) for a few hours now and I am no further forward than when I started.
@sandbags does your API endpoint return correct content-type? I had similar problem when it used to return not “application/json"
@kishanov i posted a little further up with the response Content-Type: application/json;charset=UTF-8
@sandbags Here is a working snippet from a side project that I have. Not sure if it is helpful, but looks like your endpoint might be add an extra set of strings to the response body before returning?
@nrako thanks, your code looks pretty much the same as mine modulo my use of re-frame-http-fx
sounds like an opportunity to take a break and bring a set of fresh eyes back to it after food and rest 😉
has anyone considered matching subscription keywords to clojure.spec keywords to easily map data validation?
@joshjones i think you are probably right
I’m sure a fresh perspective on it after the passage of some time will immediately reveal a simply brilliant solution 🙂
i have little doubt that, at the end of all this, i am going to discover some stupid schoolboy error that i have made
@joshjones i know, i know
if that’s the reason, hey, it’s only because we’ve all done that kind of thing, some of us multiple times
@sandbags shamless plug #2 you could try https://github.com/oliyh/martian
@oliy thank you, however I'm loathe to throw out everything i have done and embark on a new set of libraries and API's just because I am having a JSON encoding issue that is, most likely, some mistake i have made (since other people are, i guess, using re-frame-http-fx without this problem)
@sandbags What's the server side code look like? I would be especially curious about middleware...
@sandbags: This might be useless advice, but I was having some different issues getting JSON stuff to work - I switched everything to Transit to figure out where the problem was and the problems went away - my issues were JSON writing/reading specific and I was spinning my wheels thinking it was something else.
@shaun-mahood well, originally, i planned to just shovel EDN over the wire but, for some reason, i ended up using JSON
i think i've used transit before for serialising to localStorage so i might give that a go
http://jsonlint.com validates the JSON my server is responding with. The header Content-Type: application/json;charset=UTF-8
seems okay to me
my re-frame-http-fx invocation appears identical (in at least the obviously relevant areas) to the examples and what others have posted
Hi, Hoping someone can give some insight to writing a test for a Form-1 structured component. I want my test to simply assert that the hiccup returned from my component is of the correct format e.g.
(defn simple-component []
[:div "hello"])
;; test
(= (simple-component) [:div "hello"]) ;; => true
I'm invoking my component with ()
rather than []
in my test because it knows nothing of Reagent and doesn't interprete the returned value. This works fine for my simple component, however when it comes to testing a more complex component, problems occurr:
(defn simple-component []
[:div "hello"])
(defn complex-component []
[simple-component])
;; test
(= (complex-component) [:div "hello"]) ;; => false
This test fails because complex-component
uses []
to invoke simple-component
and as such the hiccup returned from complex-component
contains references to the simple-component
function rather than interpreted values.
I could update complex-component
to invoke simple-component
using ()
rather than []
however I believe this is bad practice because it will prevent simple-component
having an independent React lifecycle.
So my question (finally!) should I be invoking my component in my test with []
and attempting to interpret the returned value using Reagent? If so how do I do this?i am truly grateful, i think i had convinced myself things were okay server side but someone (maybe it was even you) did mention something about a potential double-encoding
what I did should, I think, be okay as you can return status and a body but i think i shall question this another day and move on with my life! 🙂
oh well, i got to know ajax.core a bit better and figure out how to override library methods and play with the JS debugger which is not truly horrible
@mf i guess you need to trigger a render of the hiccup somehow since otherwise its just a vector
@mf I would not test the nested generated html for multiple components. I think testing the generated html of components gets a little... eh as it is
but adding testing the nested subcomponents to that will just really tightly couple your current implementation in an unnecessary way.
if [complex-component]
is returning [simple-component]
then you know it's right and if [simple-component]
returns what you expect then you can assemble a chain of tests without trying to expand the entire markup
if necessary, I would just test that the returned hiccup will render a particular nested component:
(defn simple-component []
[:div "hello"])
(defn complex-component []
[simple-component])
;; test
(= (complex-component) [simple-component]) ;; => false
and obviously to be clear, I think the example components you've illustrated with aren't probably worth testing in the first place. I only test the hiccup for form-1 components that have conditional logic or looping etc.
If someone wants to add a class or something to some markup do you really want your test to break? What value would that give you? What would the developer do to fix the test?
The complex-component I'm testing is infact more complicated, it uses a bunch of other private components, that I don't want consumers (my test-suite being one) to know about
In either reagent or cljsjs/react there is a 'virtual Dom node' that you can mount a reagent fn into which will let you do what you want. I just wouldn't recommend it
@geoffs I want to take a behavioural approach to testing complex-component, so that the test is ignorant of the implementation details of complex-component (e.g. the private sub-components it uses)
As I see it the test is less coupled to the solution of complex-component if it knows nothing of it's internals
and you may be getting less coupling to the implementation of complex-component
at the expense of coupling directly to the implementation details of all the components that complex-component
uses... this seems like a bad trade-off to me but YMMV
@mf this is what you want:
(ns test-example.core-test
(:require [cljs.test :refer-macros [deftest testing is use-fixtures]]
[cljs-react-test.utils :as tu]
[cljs-react-test.simulate :as sim]
[dommy.core :as dommy :refer-macros [sel1]]
[reagent.core :as reagent]
[test-example.core :as core]))
(def ^:dynamic c)
(use-fixtures :each (fn [test-fn]
(binding [c (tu/new-container!)]
(test-fn)
(tu/unmount! c))))
(deftest increment-button
(testing "on-click"
(let [app-state (reagent/atom {:count 0})
_ (reagent/render [core/increment-button app-state] c)
node (sel1 c [:button])]
(is (= 0 (:count @app-state)))
(sim/click node nil)
(is (= 1 (:count @app-state))))))
this comes from https://github.com/reagent-project/reagent-cookbook/tree/master/recipes/test-example-with-ReactTestUtils
the way i personally prefer to test is like this : https://github.com/oliyh/re-learn/blob/master/test/re_learn/model_test.cljs this is testing the model with pure data, and the beauty is you could even run this test in the jvm with the latest re-frame stuff
then the view code is done with devcards, like this: https://github.com/oliyh/re-learn/blob/master/test/re_learn/devcards/lessons.cljs
it took me a while to understand what the point was, but now i get it there's no going back
i think it was when i started working on an app which had to represent lots of state in the same component
once you get above a few variables the permutations of state become too many to be able to manually shuffle your app into all those states to see what it would look like
ok, but i use it on re-learn because re-learn can display lesson bubbles in many different places - top, bottom, left, right, top-left, bottom-right...
if i had a whole sequence of lessons in all those positions i'd have to click through to see them all
so if i'm refactoring how they should appear (or adding a new one), it's immediately obvious when i've broken something and when it works
i'm planning to write something on the juxt blog about this at some point in the future (comprehensive testing of re-frame apps) but in the meantime there's a good one on devcards already by @frankie https://juxt.pro/blog/posts/generative-ui-clojure-spec.html
@geoffs Interested in why you see the testing of the outward facing behaviour of complex-component adding tighter coupling to the implementation details of simple-component
? As I see it this style of testing allows the implementation details of simple-component
to be a black box because we don't know about what it does. We just know what we expect complex-component
to return.
@mf stepped away for lunch. I may not be understanding you super well, but there's an issue with testing "the outward facing behavior" of complex-component, when what's being tested is the hiccup content of it. The exact hiccup content is a detail of the subcomponents, and really also a detail of the complex-component that I wouldn't want to be coupled to. I'm not sure if that actually explains it any differently than I did before 🙂
for the people who are interested, there is new re-frame specific job posting in #jobs
@geoffs thanks for the further clarification. My goal was to test complex-component
as a pure-function, asserting that given a specific input the returned value (hiccup) was as expected. In my case complex-component
is the only public function in my libraries namespace. complex-component
uses private components (e.g. simple-component
) in the namespace but these are not available outside the namespace. For this reason it makes sense to me to test the public component only. Anyway really appreciate your insights 🙂
I don’t know who wrote the docs
portion of re-frame, but man it’s good. Kudos @mikethompson et al for making sense of a detailed framework