Fork me on GitHub
#shadow-cljs
<
2021-10-09
>
pesterhazy14:10:26

Howdy, I'm trying to use Jest as a test runner in conjunction with shadow-cljs and I'm running into problems Here's a minimal repro https://github.com/pesterhazy/shadow-jest

pesterhazy14:10:57

Essentially it bombs out with

ReferenceError: goog is not defined

      at call (../.shadow-cljs/builds/test/dev/out/cljs-runtime/goog/debug/error.js:15:1)
      at SHADOW_IMPORT (out.js:62:44)
      at Object.<anonymous> (out.js:1522:1)

pesterhazy15:10:19

Not knowing which target was appropriate, I picked :target :node-test because the tests are intended to run in node and jsdom (with Testing Library).

pesterhazy15:10:25

Any help appreciated!

thheller16:10:35

@pesterhazy for jest you likely want to use :target :npm-module instead. :node-test is pretty specific to run cljs.test in node. you can use :ns-regexp "-test$" to get similar behavior as :node-test with regards to which files are included

pesterhazy16:10:47

ah, cool - let me give that a try

thheller17:10:03

FAIL  dist-test/todomvc.app_spec.js
  ● Test suite failed to run

    Your test suite must contain at least one test.

      at onResult (../node_modules/@jest/core/build/TestScheduler.js:175:18)
          at Array.map (<anonymous>)

thheller17:10:22

changed jest.config.js

testMatch: [
    "**/*_spec.js"
  ],

thheller17:10:42

and using this build config

{:target :npm-module
  :ns-regexp "-spec$"
  :output-dir "dist-test"}

pesterhazy17:10:57

hehe I was just typing that....

pesterhazy17:10:28

out of curiosity, have you tried jest with shadow before?

pesterhazy17:10:18

we're experimenting with it at Pitch, where we want to improve our frontend testing story

thheller17:10:23

several people have asked in the past but I never got around to it. thanks for the repo, made it really easy to try 🙂

pesterhazy17:10:56

we got it to work with the :browser-test target but that felt hacky and I thought there must be a better way

thheller17:10:24

:npm-module seems to work as far as I can tell

thheller17:10:42

even (jest) watch works

pesterhazy17:10:51

FAIL  dist-test/todomvc.app_spec.js
  ✕ arithmetic (5 ms)

  ● arithmetic

    expect(received).toBe(expected) //  equality

    Expected: 5
    Received: 4

      at Object.<anonymous> (todomvc/app_spec.cljs:9:27)

thheller17:10:53

even release seems to work so seems all good

thheller17:10:42

it source maps. that is gonna help a lot. seems good.

pesterhazy17:10:52

i'm going to hack on it some more

thheller17:10:12

I don't like the test syntax all that much but a few helper functions/macros might make that bearable

pesterhazy17:10:14

going to try to implement todomvc based on tdd using Jest + React Testing Library

pesterhazy17:10:31

yeah, we already have a wip wrapper ns for jest assertions

thheller17:10:39

there could totally be a :target :jest if needed but AFAICT :npm-module seems to do everything you'd need

pesterhazy17:10:19

would you be open to a PR to the user guide once the dust settles?

pesterhazy17:10:40

it's quite fast on incremental builds in this minimal repo

PASS  dist-test/todomvc.app_spec.js
  ✓ arithmetic (2 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.578 s, estimated 1 s
Ran all test suites.

thheller17:10:49

yeah first run seems slow but after that it appears to use some cache and only process actually changed files

thheller17:10:57

still sometimes slow for me. dunno why

pesterhazy17:10:19

I'm surprised all of this works with node's require() etc - the combination of node's require() and goog.provide etc is not something I can claim to understand

thheller17:10:02

well :npm-module basically creates some glue code to pretend we still have everything in the same global scope but actually don't

thheller17:10:29

quite hacky but make CLJS/Closure output look like commonjs for the tools that need that

thheller17:10:09

should have named it :target :commonjs but oh well naming is hard 😛

pesterhazy17:10:05

btw a mini bug report while i'm here steps • in the repo, run cp src/test/todomvc/app_spec.cljs src/test/todomvc/another_spec.cljs • in the shadow terminal Resource does not have expected namespace • compilation stops • ok fair enough, need to fix the ns decl • open that file in emacs and rename to (ns todomvc.another-spec) expected • now that I've fixed the ns decl, compilation works again actual • it doesn't compile, I need to ^C and restart • then it works

pesterhazy17:10:44

Back to implementing TodoMVC using TDD!

thheller17:10:46

btw you likely don't need to restart

thheller17:10:54

you can force trigger a recompile from the REPL or the UI

thheller17:10:25

(which of course shouldn't be necessary but still faster than a full restart)

pesterhazy17:10:16

do you mean nREPL'ing into shadow?

thheller17:10:41

well I'd assume you already have emacs connected?

pesterhazy17:10:11

hehe, I'm lazy with REPLs, I'm a bad Clojurist, but using the UI will work nicely

thheller17:10:15

from the CLJ repl (shadow.cljs.devtools.api/watch-compile! :the-build)

pesterhazy17:10:36

in CLJS I mostly rely on reloading, which often gives me 80% of what a REPL would

thheller17:10:48

yeah I barely use the CLJS REPL too. CLJ a lot though

pesterhazy17:10:38

in Clojure I use (cider-eval-buffer) and that's it

pesterhazy17:10:58

but I type a lot of stuff into the terminal repl, I'm weird that way

thheller17:10:22

shadow-cljs clj-repl it is then 😉

pesterhazy17:10:27

$ shadow-cljs clj-repl
shadow-cljs - config: /Users/user/pitch/shadow-jest/shadow-cljs.edn
shadow-cljs - connected to server
shadow-cljs - REPL - see (help)
To quit, type: :repl/quit
shadow.user=>

pesterhazy17:10:30

whoa I had no idea!

pesterhazy17:10:39

I'll use that a lot

pesterhazy17:10:45

how is this so fast?

thheller17:10:55

shadow-cljs - connected to server

pesterhazy17:10:56

it's like 10x faster than lein repl :client ....

thheller17:10:06

it is connected to the running watch you have I guess

pesterhazy17:10:31

yeah it is, but using lein as a mere nrepl client is already slow as molasses

thheller17:10:27

well yeah its not starting a new JVM. just the node script opening a tcp socket

pesterhazy17:10:00

so it's not using nREPL then?

thheller17:10:10

no, just the socket REPL

pesterhazy17:10:16

ah, so much better

pesterhazy17:10:47

(sometimes I wonder how much damage lein and nREPL, with their slowness and complexity, have done to Clojure)

thheller18:10:42

I like lein. nREPL not so much 😛

pesterhazy18:10:24

omg I just added a watch for the app build via the socket repl

pesterhazy18:10:25

(shadow.cljs.devtools.api/watch :app)
[:app] Configuring build.
[:app] Compiling ...

pesterhazy18:10:38

shadow is so nicely decomplected!

thheller18:10:58

(shadow/watch :app) from shadow.user 🙂

thheller18:10:17

I pretty much only run shadow-cljs server these days and do the rest over the UI

thheller18:10:24

guess I'm weird that way 😛

borkdude08:10:18

@pesterhazy The slowness of lein just comes from loading many dependencies every time, I think. A comparable tools.build program with clj can be equally slow, if you're not mindful about which deps you are bringing in in your namespace form.

thheller08:10:33

I think most people complaining about slow startup of lein just have a user.clj sitting on the classpath that contributes most of the slowness. Otherwise IMHO its fine.

pesterhazy09:10:23

Well, I think an argument can be made that lein tries to do too may things, so it ends up not doing any of these well. But of course I shouldn't have said "damage". We owe a lot to lein's original authors, and I'm in no position to complain, having written little in the way of OSS

pesterhazy17:10:41

I think Stu Halloway has a talk out where he says "don't type stuff into the repl" - I beg to disagree