Liking cljdoc? Tell your friends :D

react-testing-library-cljs

Clojars Project

The react-testing-library-cljs library provides a ClojureScript functions for the react-testing-library to simplify interop.

For more information about the principles and concepts behind the testing library, you can visit the official react-testing-library website.

Features

Common

  • The react-testing-library-cljs.screen namespace provides a wrapper around the react-testing-library's screen object, making it easier to interact with rendered components.

  • The react-testing-library-cljs.fire-event namespace simplifies firing events on rendered components, allowing you to simulate user interactions.

  • The react-testing-library-cljs.within namespace scopes queries to a specific element, useful when multiple similar elements exist in the DOM.

Reagent

  • The react-testing-library-cljs.reagent.fire-event similar to the react-testing-library-cljs.fire-event, but calling reagent.core/flush after every event to trigger re-render.

  • The react-testing-library-cljs.reagent.render provides helper function to render reagent components.

Installation

Add the library to your project:

deps.edn

org.clojars.olecve/react-testing-library-cljs {:mvn/version "0.0.16"}

Leiningen

[org.clojars.olecve/react-testing-library-cljs "0.0.16"]

Install the npm dependency:

npm install --save-dev @testing-library/react

shadow-cljs config

Add a :node-test build target:

;; shadow-cljs.edn
{:builds
 {:test {:target :node-test
         :output-to "out/test.js"}}}

Run tests with:

npx shadow-cljs compile test && node --require global-jsdom/register out/test.js

Usage

Rendering & querying

(ns my-app.core-test
  (:require [cljs.test :refer [deftest is]]
            [react-testing-library-cljs.reagent.render :as render]
            [react-testing-library-cljs.screen :as screen]))

(defn greeting []
  [:h1 "Hello, world!"])

(deftest renders-greeting
  (render/render! [greeting])
  (is (some? (screen/get-by-text "Hello, world!"))))

Firing events

(ns my-app.events-test
  (:require [cljs.test :refer [deftest is]]
            [react-testing-library-cljs.reagent.render :as render]
            [react-testing-library-cljs.reagent.fire-event :as fire-event]
            [react-testing-library-cljs.screen :as screen]
            [reagent.core :as r]))

(defn counter []
  (let [count (r/atom 0)]
    (fn []
      [:button {:on-click #(swap! count inc)}
       (str "Count: " @count)])))

(deftest click-increments-counter
  (render/render! [counter])
  (render/act #(fire-event/click (screen/get-by-text "Count: 0")))
  (is (screen/get-by-text "Count: 1")))

Mocks

(ns my-app.mocks-test
  (:require [cljs.test :refer [deftest is]]
            [react-testing-library-cljs.mocks :as mocks]
            [react-testing-library-cljs.reagent.render :as render]
            [react-testing-library-cljs.fire-event :as fire-event]
            [react-testing-library-cljs.screen :as screen]))

(deftest tracks-button-click
  (let [[calls on-click] (mocks/create)]
    (render/render! [:button {:on-click on-click} "Submit"])
    (fire-event/click (screen/get-by-text "Submit"))
    (is (= 1 (count @calls)))))

Scoped queries with within

Use within to scope queries to a subtree — useful when the same elements appear in multiple places. In the example below, scoping to the dialog avoids ambiguity with other "Delete" buttons on the page:

(ns my-app.within-test
  (:require [cljs.test :refer [deftest is]]
            [react-testing-library-cljs.reagent.render :as render]
            [react-testing-library-cljs.screen :as screen]
            [react-testing-library-cljs.within :as within]))

(defn page []
  [:div
   [:ul
    [:li "Report Q4" [:button "Delete"]]
    [:li "Report Q3" [:button "Delete"]]]
   [:div {:role "dialog" :aria-label "Confirm deletion"}
    [:p "Are you sure you want to delete this report?"]
    [:button "Delete"]
    [:button "Cancel"]]])

(deftest confirm-dialog-has-correct-actions
  (render/render! [page])
  (let [dialog (screen/get-by-role "dialog")]
    (is (some? (within/get-by-role dialog "button" {:name "Delete"})))
    (is (some? (within/get-by-role dialog "button" {:name "Cancel"})))))

Async queries

find-by-* queries return a promise that resolves when a matching element appears (useful for async updates):

(ns my-app.async-test
  (:require [cljs.test :refer [deftest async is]]
            [react-testing-library-cljs.reagent.render :as render]
            [react-testing-library-cljs.screen :as screen]))

(deftest finds-async-element
  (async done
    (render/render! [my-async-component])
    (-> (screen/find-by-text "Loaded!")
        (.then (fn [element]
                 (is (some? element))
                 (done))))))

Release

Prerequisites:

  • GPG configured (lein help gpg)
  • Clojars credentials in ~/.lein/profiles.clj:
{:auth {:repository-auth {#"clojars" {:username "USERNAME" :password "CLOJARS_TOKEN"}}}}

Run:

bb release

LICENSE

MIT

Can you improve this documentation?Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close