Fork me on GitHub
#re-frame
<
2018-01-11
>
cmal02:01:50

Thanks @mikethompson. Just feeling frustrating using D3.js with re-frame, because of the un-immutability nature of D3.js.

cmal02:01:33

BTW, do you have any examples about vega with re-frame?

mikethompson02:01:53

(previous link corrected)

cmal02:01:40

Thank you, @mikethompson. I will have a look.

genRaiy12:01:34

I tried phantom.js but it failed - does not support FormData šŸ˜±

genRaiy12:01:51

anyway, it turns out that headless chromium is a thing

genRaiy12:01:57

so that all works nicely

genRaiy12:01:47

in conjunction with puppeteer .. all can be ran in a CI

borkdude13:01:14

@raymcdermott Weā€™re using headless Chrome, but headless Firefox is now also a thing

borkdude13:01:31

@raymcdermott running it in a Docker container, so nothing fancy to install on our CI server

borkdude13:01:25

several ways to do it, but we try to avoid node šŸ™‚

genRaiy13:01:12

LOL I wonder why ā€¦ itā€™s such a stable genius

borkdude13:01:09

This wrapper around webdriver API makes things easy for us: https://github.com/igrishaev/etaoin All from JVM -> Docker container running ChromeDriver / headless Chrome

borkdude13:01:36

There was also a good Clojure wrapper around Selenium but it was abandoned.

manutter5113:01:53

Wow, etaoin looks very interesting, thanks for mentioning it.

genRaiy14:01:37

so maybe Iā€™m doing it wrong ā€¦ can you drive the non-visuals (dispatch / subscribe) type tests from etaoin?

borkdude14:01:09

What does your test look like? As in, what does your assertion look like?

borkdude14:01:48

We donā€™t test at that level. Just ā€œuser visits this page, does this and that, and then this should be on the screenā€.

borkdude14:01:41

But you could, using JS execution.

genRaiy14:01:32

I canā€™t add code snippets here

genRaiy14:01:48

Iā€™ll put in the main page

borkdude14:01:05

or msg me privately, also fine

genRaiy15:01:20

I think the discussion is OK in the forum - no?

borkdude15:01:27

I think so.

borkdude14:01:42

@raymcdermott E.g. like this, you could execute JS:

(eta/js-execute
  *chrome*
  "$(\".title-text:contains('Frequency Table')\")[0].scrollIntoView()"))
(code is now obsolete, because etaoin has a scroll function now)

genRaiy14:01:19

seems not as good though šŸ™‚

genRaiy14:01:58

using two tools is not the end of the world for sure

borkdude14:01:09

@raymcdermott why are you testing on this level instead of filling the form on the UI level?

genRaiy14:01:10

both methods of testing seem legit

borkdude14:01:40

sure, just curious. still need another form of testing on the UI level to ensure nothing breaks there

borkdude14:01:04

I guess itā€™s like unit vs integration testing, both have their purpose

borkdude14:01:33

but maybe node or something is a better fit for this kind of testing, since you donā€™t even need a browser for this

genRaiy14:01:26

re-frame is meant for browsers though and there are some things (like FormData for example) that might not work so easily on node.js

genRaiy14:01:49

I mean they might but thatā€™s not the point of node

borkdude15:01:27

ok, you could start the test from within the app using etaoin js execution and then read the browser logs to see if the test ran ok or not.

borkdude15:01:20

I think my suggestion may be not a good one then, because we test on a higher level. Good luck!

borkdude16:01:14

(re 4:01PM, actually etaoin returns the result from the js expression as well, so if your tests are totally sync that would also work)

genRaiy16:01:12

@borkdude some things talk to servers async ā€¦ but anyway who here wants to code in JS though? OK as a hack but would prefer to keep the code in CLJS and the infra can be node JS or browser JS as needed

genRaiy16:01:01

using npm / chrome are all a bit annoying

borkdude16:01:21

yeah, I meant your re-frame test. it says run-test-sync so I thought that could work

genRaiy16:01:24

itā€™s kind of shocking to me that a headless browser env is not first class for devs

genRaiy16:01:22

@borkdude I donā€™t know how that code helps tbh

genRaiy16:01:10

the js code with scrolltoview

genRaiy16:01:33

maybe it was just a sample of what was possible?

borkdude16:01:55

ok, itā€™s just showing how you can execute JS. In your case it would be (eta/js-execute ā€œ(whatever-test)ā€œ) and then assert from the JVM that everything is fine

borkdude16:01:22

FWIW, Iā€™m using this Docker to spin up a headless chrome: https://hub.docker.com/r/robcherry/docker-chromedriver/

borkdude16:01:22

but during development Iā€™m not using a headless one btw, I want to look at what itā€™s doing

genRaiy16:01:27

how does the JVM report on the tests?

genRaiy16:01:13

re non-headless ā€¦ yes, sure

borkdude16:01:39

well, you can use regular clojure.test to drive etaoin. e.g. https://github.com/igrishaev/etaoin#writing-integration-tests-for-your-application but Iā€™ve written my own glue between clojure.test and etaoin

borkdude16:01:00

you can do e.g. (is (= 3 (eta/js-execute "1+2"))), but Iā€™m not sure how far you would get with that

genRaiy16:01:34

Iā€™m getting confused about why I would use js-execute

genRaiy16:01:48

the other stuff all seems nice / legit

borkdude16:01:59

to execute your re-frame test inside the browser

genRaiy16:01:03

so I must be missing something obvious

borkdude16:01:58

I am assuming this code runs inside a browser where your app is loaded, no? https://clojurians.slack.com/files/U04V5V0V4/F8RCVN0JW/re-frame-tests.clj

genRaiy16:01:01

oh, I see - use that instead of Karma

genRaiy16:01:40

sorry, I was a bit slow there

borkdude16:01:45

right. but again, Iā€™m not sure how nice that would be to work with. np

genRaiy16:01:47

ok, thanks though ā€¦ I now get that itā€™s an option

genRaiy16:01:32

though does look a bit yucky tbh ā€¦. but then everything has some yuck on it šŸ˜‰

borkdude16:01:53

itā€™s the law of conservation of yuck

genRaiy16:01:40

btw are you going to clojured?

borkdude16:01:57

Iā€™m hesitant, because itā€™s only one dayā€¦ the travel would be longer than the fun

genRaiy16:01:03

I know what you mean ā€¦. but weā€™re having a defn road trip ā€¦ both Vijay and myself will be talking

borkdude16:01:31

Iā€™m looking forward to the report in one of the next defn episodes!

genRaiy16:01:52

haha yes we will be sure to do that

genRaiy16:01:45

btw, the etaoin integration test is the first moment that I have used a dynamic var!

borkdude16:01:04

yeah, Iā€™m also doing that

genRaiy16:01:05

scary šŸ˜±

borkdude16:01:20

actually in tests itā€™s the only place where I use it

genRaiy16:01:38

yes, should be safe

borkdude16:01:57

test code is more yuck-accepting

borkdude16:01:02

yuck-forgiving

genRaiy16:01:16

yuck-creating

genRaiy16:01:25

we need a yuck management system

genRaiy16:01:41

oh yeah - clojure šŸ™‚

borkdude16:01:54

Clojure is the lotus built upon the mud

borkdude16:01:45

definitely coming to Dutch Clojure Days though

genRaiy16:01:09

likewise ā€¦ so see you there

genRaiy16:01:26

should be a vegetable weekend to remember

borkdude16:01:41

betacarotene overdose

genRaiy16:01:49

friendly reminder - this is a not a porn server

genRaiy16:01:04

and the slack emoji set does not include a carrot!

borkdude16:01:24

whoā€™s thinking of porn here then?

genRaiy16:01:49

betacarotene is my safe word

borkdude16:01:23

Btw, I hope you read the CoC (code of conduKt) for ClojureD?

genRaiy16:01:44

lol Iā€™ll try to keep it clean

genRaiy16:01:57

but I see what you did there

borkdude16:01:06

Reinheitsgebot is a thing in Germany

genRaiy16:01:34

these are the marks of a truly civilised society

genRaiy17:01:04

no chlorine in the beer / chickens

genRaiy17:01:23

quick question ā€¦.

genRaiy17:01:33

assuming you have a login button

genRaiy17:01:45

how do you test for itā€™s visibility?

genRaiy17:01:05

(I canā€™t see a way to provide an ID in reframe)

genRaiy17:01:39

I have tried {:class :rc-button.btn.btn-default} without luck

genRaiy17:01:07

<button class="rc-button btn btn-default" style="flex: 0 0 auto;">Login</button>

genRaiy18:01:24

the class has spaces so I donā€™t know how to transpose that

borkdude19:01:55

do you mean from etaoin?

borkdude08:01:54

I do it like this:

(defn contains-text? [text]
  (format ā€œ//*[contains(text(),ā€˜%sā€™)]ā€ text))

(defn contains-class? [class]
  (format ā€œ//*[contains(@class, ā€˜%sā€™)]ā€ class))

borkdude08:01:53

and then e.g.:

(eta/wait-exists *chrome* [{:tag :div :class ā€œsearch-summary-textā€}
                                 (contains-text? ā€œresultsā€)])

genRaiy08:01:32

ok, nice ā€¦. thanks, Iā€™ll give it a shot

borkdude08:01:44

note that when you use :class it only matches on the full class, so this is a workaround for it

genRaiy08:01:37

hmmm doesnā€™t that effectively replace your contains-text function?

borkdude08:01:30

Not sure about that

genRaiy08:01:21

chasing the code, it runs query which seems to include matches like you have in your fn

genRaiy08:01:45

A query might be: - a string, so the current browserā€™s locator will be used. Examples: //div[@id=ā€˜contentā€™] for XPath, div.article for CSS selector

genRaiy08:01:21

anyway ā€¦ Iā€™ll give that a shot first and see how it goes šŸ™‚

borkdude08:01:17

I gave you an example with a query.

[{:tag :div :class "search-summary-text"}
                                 (contains-text? "results")]
means: search for an element with class ā€¦ which has a child element that contains text ā€¦.

borkdude08:01:50

has-class seems to do the same thing yeah, has-text is also there. It didnā€™t exist when I wrote this. Iā€™m an early adopter šŸ™‚

genRaiy08:01:14

haha well at least it means Iā€™m not cracking up

borkdude08:01:12

cracking up?

genRaiy08:01:24

going crazy

genRaiy08:01:59

sorry Iā€™m an idiom idiot

borkdude08:01:35

well, I learned English mainly by watching TV, but it only goes so far

genRaiy08:01:41

I tried to learn Flemish by watching TV but I can only endure one form of punishment at a time

genRaiy09:01:57

itā€™s actually even simpler ā€¦

genRaiy09:01:11

this works (wait-visible {:class "rc-button btn btn-default"})

borkdude09:01:05

yes, that also works, but youā€™d have to specify the full class. also visible can cause unexpected results, because in some cases the element never becomes visible. Thatā€™s why I use wait-exists instead

borkdude09:01:23

visible depends on the viewport your using

genRaiy09:01:28

sure ā€¦ but in this case it must become visible (login) or we are screwed šŸ˜‰

genRaiy09:01:47

but I take your general point

borkdude09:01:35

yeah, sometimes the user has to scroll a bit

borkdude09:01:19

working with the full class works, until you add a classā€¦ e.g. ā€œactiveā€, then it quickly breaks

genRaiy09:01:40

yeah, this is baby steps for me

genRaiy09:01:57

and babies fall over all the time

genRaiy09:01:10

but itā€™s exciting šŸ™‚

borkdude09:01:21

yeah, it takes a few babies to get there, but itā€™s worth it

genRaiy09:01:13

thanks for picking me up off the floor and getting me walking again

borkdude09:01:07

The nice thing about etaoin is that itā€™s just a simple wrapper around an API, so if something is missing, just add a clj-http call somewhere

borkdude09:01:27

much better than Selenium Java crap if you ask me

borkdude10:01:35

Thanks for the heads up via Patreon šŸ˜›

borkdude11:01:26

Oh, I thought you sent it

borkdude11:01:32

but then it must be Vijay

genRaiy11:01:10

sent what?

genRaiy11:01:58

LOL yes he just informed me in another window

genRaiy11:01:42

if you have a question about the impact of post-Hegelian idealism on Clojure, now is your chance

genRaiy13:01:45

am trying to do an oauth2 flow using auth0 and it all works fine with chrome but fails when running headless ā€¦. have you seen anything like that?

genRaiy13:01:13

[ I can open an issue of course but just wondering ]

borkdude13:01:22

maybe itā€™s the visible/exists issue?

genRaiy13:01:45

I played with that in one or two steps without success

genRaiy13:01:54

but let me check

borkdude13:01:15

Iā€™d also make a screenshot for debugging

borkdude13:01:52

+ you can execute some arbitrary js to test for elements etc. for debugging from the REPL

genRaiy13:01:42

seems like the auth0 overlay has to be visible

borkdude13:01:27

REPL your way through it

genRaiy13:01:08

I have used the REPL to build the script visually ā€¦ I live the dream

borkdude13:01:57

How do Haskell people even get by. The type system doesnā€™t help you in any way with issues like this.

borkdude14:01:33

I mean any language without a real REPL

borkdude14:01:02

Donā€™t have anything to ask Zach, except to thank him for Aleph, the fundamental thing in Yada that we are gratefully using

genRaiy15:01:34

agreed on REPL

genRaiy15:01:57

you have time to think on Zach but yes, we are all grateful for aleph

genRaiy16:01:58

seems like the google oauth2 form changes whether visible or not šŸ˜ž

genRaiy16:01:10

but yeah, amazing tools we have

borkdude16:01:33

didnā€™t understand

genRaiy16:01:21

when running chrome normally I get a different login form (different field names) from the one I get when running headless

borkdude16:01:41

ah tricky. whyyyyy.

genRaiy16:01:51

fuck knows

genRaiy16:01:12

but nice tools so that I could discover it šŸ™‚

genRaiy16:01:44

being able to grab the html is killer