{"id":29097397,"url":"https://github.com/lambdaisland/chui","last_synced_at":"2025-08-09T09:18:03.021Z","repository":{"id":43274670,"uuid":"250249038","full_name":"lambdaisland/chui","owner":"lambdaisland","description":null,"archived":false,"fork":false,"pushed_at":"2023-08-01T04:09:09.000Z","size":583,"stargazers_count":66,"open_issues_count":2,"forks_count":10,"subscribers_count":8,"default_branch":"main","last_synced_at":"2025-07-31T02:20:08.686Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"epl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lambdaisland.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2020-03-26T12:12:27.000Z","updated_at":"2025-05-01T13:49:59.000Z","dependencies_parsed_at":"2024-04-23T08:49:38.673Z","dependency_job_id":"af180448-946e-4e8d-9308-cffe28da9c8d","html_url":"https://github.com/lambdaisland/chui","commit_stats":{"total_commits":187,"total_committers":12,"mean_commits":"15.583333333333334","dds":"0.19786096256684493","last_synced_commit":"9c1e1b5bfb4fca630522d3a1c766de6fa6ccf6fc"},"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"purl":"pkg:github/lambdaisland/chui","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lambdaisland%2Fchui","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lambdaisland%2Fchui/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lambdaisland%2Fchui/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lambdaisland%2Fchui/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lambdaisland","download_url":"https://codeload.github.com/lambdaisland/chui/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lambdaisland%2Fchui/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268696897,"owners_count":24292383,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-04T02:00:09.867Z","response_time":79,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-06-28T13:42:08.668Z","updated_at":"2025-08-09T09:18:02.980Z","avatar_url":"https://github.com/lambdaisland.png","language":"Clojure","funding_links":["http://opencollective.com/lambda-island"],"categories":[],"sub_categories":[],"readme":"# chui\n\n\u003c!-- badges --\u003e\n[![cljdoc badge](https://cljdoc.org/badge/lambdaisland/chui)](https://cljdoc.org/d/lambdaisland/chui) [![Clojars Project](https://img.shields.io/clojars/v/lambdaisland/chui.svg)](https://clojars.org/lambdaisland/chui)\n\u003c!-- /badges --\u003e\n\nModern ClojureScript test runner\n\n![Screenshot of the Chui UI in action](screenshot_.png)\n\n## 錘 (锤) [chuí]\n\n(rhymes with \"hey\")\n\n- hammer\n- to hammer into shape\n- weight (e.g. of a steelyard or balance)\n\nSee the [Line Dict entry](https://dict.naver.com/linedict/zhendict/dict.html#/cnen/entry/cf6a566ba4a64496b8d8610525f3d9e8) for an audio sample.\n\n### Funded by Pitch\n\nWe want to thank [Pitch](https://pitch.com) for funding the initial development\nof Chui, and their continuing support of the Clojure and ClojureScript\necosystem.\n\n\u003c!-- opencollective --\u003e\n\n\u0026nbsp;\n\n\u003cimg align=\"left\" src=\"https://github.com/lambdaisland/open-source/raw/master/artwork/lighthouse_readme.png\"\u003e\n\n\u0026nbsp;\n\n## Support Lambda Island Open Source\n\nchui is part of a growing collection of quality Clojure libraries and\ntools released on the Lambda Island label. If you are using this project\ncommercially then you are expected to pay it forward by\n[becoming a backer on Open Collective](http://opencollective.com/lambda-island#section-contribute),\nso that we may continue to enjoy a thriving Clojure ecosystem.\n\n\u0026nbsp;\n\n\u0026nbsp;\n\n\u003c!-- /opencollective --\u003e\n\n## Motivation\n\nThe testing library that comes with ClojureScript, `cljs.test`, consists of two\nparts: an API for expressing tests and assertions, and a test runner for\nexecuting tests. Chui re-implements the test runner part in a way that allows\nmore dynamic and fine-grained control, so that it forms a better base for\ntooling. It also offers an attractive browser-based UI for running tests and\ninspecting results.\n\nSee the [Architecture Decision Log](doc/architecture_decision_log.org) for\ntechnical background.\n\n## Installation\n\ndeps.edn\n\n``` clojure\nlambdaisland/chui {:mvn/version \"1.2.205\"}\n```\n\nproject.clj\n\n``` clojure\n[lambdaisland/chui \"1.2.205\"]\n```\n\n\n## Quickstart with shadow-cljs\n\nThe easiest way to use this right now is with Shadow-cljs's `:browser-test` target.\n\nUse the `lambdaisland.chui.shadow.browser-runner` namespace as your\n`:runner-ns`, and you should be good to go.\n\n``` clojure\n{:dev-http\n {8888 \"classpath:public\"}\n\n :builds\n {:test\n  {:target     :browser-test\n   :runner-ns  lambdaisland.chui.shadow.browser-runner\n   :test-dir   \"resources/public\"\n   :asset-path \"/ui\"\n   :ns-regexp  \"-test$\"}}}\n```\n\nThis assumes that you are using the `index.html` generated by Shadow. If you're\nserving your own `index.html` then make sure it contains a call to\n`lambdaisland.chui.shadow.browser-runner/init`.\n\n## Use with other tools\n\nThe main reason we recommend shadow-cljs's `:browser-test` is that it will find\ntest namespaces on the filesystem, and automatically add them to your build as\ndependencies of the test runner namespace. When using other tools you have to do\nthat manually, as so far no other tools have this functionality, but we hope\nsomething like this will become more widely available, either in ClojureScript\nitself, or in common tools.\n\nHere's what a main namespace that starts Chui and runs your tests looks like.\n\n``` clojure\n(ns my.test.runner\n  (:require [goog.dom :as gdom]\n            [lambdaisland.chui.runner :as runner]\n            [lambdaisland.chui.ui :as ui]\n            [lambdaisland.chui.test-data :as test-data]\n\n            ;; Add all your test namespaces as dependencies, to make sure they\n            ;; are part of the build, and that they are compiled *before* this\n            ;; namespace gets compiled. This is imporant for chui to find your\n            ;; tests.\n            my.foo-test\n            my.bar-test\n            my.baz-test))\n\n;; This is a macro that inspects the cljs compiler environment to find\n;; information about which tests there are, and then injects this information\n;; into the build so that it's available to Chui.\n(test-data/capture-test-data!)\n\n(defn start\n  \"Start a test run, this is the same as pressing the Test button in the UI. You\n  can run this after hot-reloading code.\"\n  []\n  (js/window.requestIdleCallback\n   #(ui/run-tests)))\n\n(defn stop\n  \"Interrupt the current test run, calls the done callback when done. Can be used\n  as a pre-hook before hot code reloading.\"\n  [done]\n  (runner/terminate! done))\n\n(defn ^:export init\n  \"Mount the Chui UI and kick off a test run, call this upon first page load.\"\n  []\n  (let [app (gdom/createElement \"div\")]\n    (gdom/setProperties app #js {:id \"chui-container\"})\n    (gdom/append js/document.body app))\n  (ui/render! (.getElementById js/document \"chui-container\"))\n  (start))\n```\n\n## Usage instructions\n\nThe Chui UI has four columns. The first one contains a list of all your tests\nnamespaces, as well as a search box and a test button.\n\nThe button kicks off a test run, by default it runs all tests, but you can\nnarrow that down by either selecting tests manually in the list, or by putting a\nquery in the search box. By default this does a simple string search, but you\ncan use the \"regexp\" checkbox in the top bar to treat the input as a regex\npattern.\n\nThe second column from the left contains a history of all your test runs. For\neach run you see a regular progress bar, and below that a visual overview of the\ntest run, as a green/orange/red bar split across multiple lines.\n\nYou can think of this bar as being similar to the output you get in\nterminal-based test runners:\n\n```\n.........E.......FFF...........\n```\n\nEach bit of the bar represents a single assertion, colored green if the\nassertion passes, orange if it fails, and red if it threw an error. The bar is\nsubdivided in namespaces and test vars. You can hover over each bit to see which\nnamespace/var it refers to.\n\nBelow this visualization you get a summary, number of tests, assertions,\nfailures and errors.\n\nThe third column shows you more details for the selected test run. By default\nthe latest test run gets selected, but you can select older ones if you want to\ninspect previous results.\n\nThis third column shows namespaces and test vars. Note that if you have a lot of\ntests this can become hard to navigate, this is why you can enable the checkbox\nto hide passing tests.\n\nFinally the fourth column shows the individual assertions, with full details.\nWhich assertions are visible depends on the selection in the third column. By\ndefault all failing assertions are shown.\n\n### Limitations\n\nFixtures must use the `:before` / `:after` syntax. We don't support synchronous\nfixtures.\n\n### Promise-based async tests\n\nChui is able to detect that a `deftest` returns a JavaScript promise, and treat\nthat as indicating it is an asynchronous test, so that Chui waits for the\npromise to resolve.\n\nIn vanilla `cljs.test` you would `cljs.test/async` for such tests, but this is a\nuseful extension for people already relying on promises in their code.\n\nBecause this is a non-compatible extension this behavior is opt-in. To turn it\non, add this to your ClojureScript compiler options:\n\n``` clojure\n{\n :closure-defines {lambdaisland.chui.runner.PROMISE_ASYNC_TEST true}\n\n }\n```\n\n## License\n\nCopyright \u0026copy; 2020 Arne Brasseur and Contributors\n\nLicensed under the term of the Eclipse Public License 1.0, see LICENSE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flambdaisland%2Fchui","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flambdaisland%2Fchui","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flambdaisland%2Fchui/lists"}