3

I am trying to migrate ClojureScript tests from "Chrome Headless" to jsdom using Karma and shadow-cljs as test runners.

The regular tests which require access to DOM or browser API work fine. But async test where cljs.core.async/go is used doesn't work. Basically, nothing inside go is executed.

Does anyone have some idea what could be wrong? Did I miss some configuration? Is it only jsdom issue or maybe it is cljs.core.async interoperability issue?

I have put a simple test example below

(ns async-tests
  (:require [cljs.test :refer [deftest async]]
            [cljs.core.async :refer [go <! timeout]]))

(deftest async-go-test
  (async done
    (.log js/console "Before go is printed")
    (go
      (.log js/console "After go is never printed")
      (<! (timeout 1))
      (done))))

The result I get in console is

LOG: 'Testing async-tests'
LOG: 'Before go is printed'
WebKit 537.36 (undefined 0.0.0): Executed 159 of 185 SUCCESS (0 secs / 0.589 secs)
WebKit 537.36 (undefined 0.0.0) ERROR
Disconnected, because no message in 30000 ms.

Versions of libraries which are used:

  "devDependencies": {
    "jsdom": "^16.4.0",
    "karma": "^5.2.3",
    "karma-cljs-test": "^0.1.0",
    "karma-jsdom-launcher": "^8.0.2",
    "shadow-cljs": "2.10.19"
  }

Karma configuration:

module.exports = function (config) {
    config.set({
        browsers: ['jsdom'],
        basePath: 'target',
        files: ['ci.js'],
        frameworks: ['cljs-test'],
        colors: true,
        logLevel: config.LOG_INFO,
        client: {
            args: ["shadow.test.karma.init"]
        },
        jsdomLauncher: {
            jsdom: {
                resources: "usable",
                runScripts: "dangerously",
                pretendToBeVisual: true
            }
        }
    })
};

1 Answers1

3

I would like to say "Thank you" to the Clojure community which helped me find a workaround for this issue and especially @thheller. The root cause is not found yet but probably that it is the result of using the range of different libraries.

Workaround

You have to override goog.async.nextTick method for your tests with js/setTimeout

Example

Create jsdom-setup namespace

(ns jsdom-setup)

(set! (.. js/window -goog -async -nextTick) js/setTimeout)

and add it to the tests JS output inside 'shadow-cljs.edn'

:builds {:karma {:target :karma
                 :output-to  "output/tests-bundle.js"
                 :ns-regexp "(setup-jsdom|[.-]tests$)"}}

Links

Clojure Slack discussion

  • Using the solution mentioned here results in "TypeError TypeError: Illegal invocation" when I call `js/goog.async.nextTick` right after. Using ` [org.clojure/clojurescript "1.11.60"]`. I think the problem is we need to `bind` the fn to the correct `this` value? Perhaps this solution used to work due to something in closure being less strict? – Dereference May 04 '23 at 18:15