### Example Test Suite Program in Clojure Source: https://github.com/weissjeffm/test.tree/blob/master/README.org This example demonstrates a basic test suite structure using test.tree. It includes group setup/teardown, nested tests, and data-driven testing setup. Ensure 'calc.test' namespace is available. ```clojure (require 'calc.test) (use 'test.tree.script) (defgroup simple-calc-tests :group-setup calc.test/open-app :group-teardown calc.test/close-app (deftest "enter numbers" (calc.test/enter-number 123) (assert (= (calc.test/current-display "123"))) (deftest "clear display" (calc.test/enter-number 234) (calc.test/clear-display) (assert (= (calc.test/current-display ""))) (deftest "add numbers" :data-driven true ``` -------------------------------- ### Define Group with Test Setup and Teardown Source: https://github.com/weissjeffm/test.tree/blob/master/README.org Configures a test group to run a setup function before each test and a teardown function after each test. The setup function clears the display in this example. ```clojure (defgroup calc-division-tests :test-setup (fn [& _] (calc.test/clear-display)) (deftest ... ) (deftest ... ) ... ) ``` -------------------------------- ### Configure test setup in a group Source: https://github.com/weissjeffm/test.tree/blob/master/README.md Use :test-setup to execute a function before every test in a group, optionally accepting test data as arguments. ```clojure (defgroup calc-division-tests :test-setup (fn [& _] (calc.test/clear-display)) (deftest ... ) (deftest ... ) ... ) ``` -------------------------------- ### Configure Simple Parallel Test Execution Source: https://context7.com/weissjeffm/test.tree/llms.txt Define a group of tests and run them in parallel using a specified number of threads. This example demonstrates basic parallel execution. ```clojure (require '[test.tree :as tt]) (require '[test.tree.script :refer [deftest defgroup]]) ;; Simple parallel execution (defgroup parallel-tests (deftest "test 1" (Thread/sleep 1000) (assert true)) (deftest "test 2" (Thread/sleep 1000) (assert true)) (deftest "test 3" (Thread/sleep 1000) (assert true)) (deftest "test 4" (Thread/sleep 1000) (assert true))) ;; Run with 4 threads (tests run in ~1 second instead of ~4) (tt/run-suite parallel-tests {:threads 4}) ``` -------------------------------- ### Aggregate Multiple Test Groups in Clojure Source: https://github.com/weissjeffm/test.tree/blob/master/README.md This example shows how to combine multiple test groups, such as 'simple-calc-tests', 'scientific-calc-tests', and 'trig-calc-tests', into a single 'all-tests' group for execution. The '-main' function then runs this aggregated suite. ```clojure (defgroup all-tests simple-calc-tests scientific-calc-tests trig-calc-tests) (defn -main [ & args] (test.tree/run-suite all-all-tests)) ``` -------------------------------- ### Configure Test Suite with Threads and Thread Runner Source: https://github.com/weissjeffm/test.tree/blob/master/README.org Configures a test suite to run with a specified number of threads and defines a custom thread runner function. The thread runner handles setup (opening a browser) and teardown (closing the browser) for each thread. ```clojure (def tests-to-run (with-meta all-calc-tests {:thread-runner (fn [run-tests] (open-my-browser "firefox") (run-tests) (close-my-browser)) :threads 5} (defn -main [ & args] (test.tree/run-suite all-calc-tests)) ``` -------------------------------- ### Configure Parallel Execution with Thread Wrapper Source: https://context7.com/weissjeffm/test.tree/llms.txt Utilize a thread wrapper function to manage resources on a per-thread basis, such as opening and closing a browser instance. The wrapper ensures setup and teardown logic is executed for each thread. ```clojure ;; Thread wrapper for per-thread resource management (defn browser-thread-wrapper [run-tests] (let [browser (atom {:id (rand-int 1000)})] (println "Thread starting - opening browser" @browser) (try (run-tests) (finally (println "Thread ending - closing browser" @browser))))) (tt/run-suite parallel-tests {:threads 4 :thread-wrapper browser-thread-wrapper}) ``` -------------------------------- ### Configure global test run options Source: https://github.com/weissjeffm/test.tree/blob/master/README.md Pass a configuration map to run-suite to control thread count and thread-level setup/teardown logic. ```clojure (defn -main [ & args] (test.tree/run-suite all-calc-tests {:thread-runner (fn [run-tests] (open-my-browser "firefox") (run-tests) (close-my-browser)) :threads 5})) ``` -------------------------------- ### Run Simple Calculator Tests Source: https://github.com/weissjeffm/test.tree/blob/master/README.org Executes a suite of simple calculator tests. This is typically the entry point for running a defined set of tests. ```clojure (defn -main [ & args] (test.tree/run-suite simple-calc-tests)) ``` -------------------------------- ### run-suite - Execute Test Tree with Reports Source: https://context7.com/weissjeffm/test.tree/llms.txt The `run-suite` function is the primary entry point for running tests. It executes all tests in the tree, blocks until completion, writes JUnit and TestNG XML reports to the current directory, and returns the test reports. ```APIDOC ## run-suite - Execute Test Tree with Reports ### Description Executes all tests in the tree, blocks until completion, writes JUnit and TestNG XML reports to the current directory, and returns the test reports. ### Method `clojure.core/->` (function call) ### Endpoint N/A (Library function) ### Parameters #### Arguments - **test-tree** (map or vector) - Required - The test tree structure to execute. - **options** (map) - Optional - Configuration options for test execution. - **:threads** (integer) - Number of threads to use for parallel execution. ### Request Example ```clojure (require '[test.tree :as tt]) (require '[test.tree.script :refer [deftest defgroup]]) ;; Define a simple test tree (defgroup my-tests (deftest "login test" (assert (= 1 1)) (deftest "create user" (assert (not (nil? "user-123"))))) ;; Run the test suite - blocks until all tests complete ;; Writes report.clj, testng-report.xml, and junitreport.xml (def results (tt/run-suite my-tests {:threads 4})) ;; Examine results (doseq [[test report] results] (println (:name test) "->" (-> report :report :result))) ``` ### Response #### Success Response (200) - **results** (map) - A map where keys are test definitions and values are their corresponding reports. #### Response Example ```clojure ;; Example output from examining results: ;; login test -> :pass ;; create user -> :pass ``` ``` -------------------------------- ### Define Test Groups with Setup/Teardown Source: https://context7.com/weissjeffm/test.tree/llms.txt Use `defgroup` to create named test collections with optional group-level and test-level setup/teardown functions. Groups can also wrap tests for resource management. ```clojure (require '[test.tree.script :refer [deftest defgroup]]) (require '[test.tree :as tt]) ;; Group with setup and teardown (defgroup database-tests :group-setup (fn [] (println "Starting database...")) :group-teardown (fn [] (println "Stopping database...")) :test-setup (fn [& _] (println "Beginning transaction...")) :test-teardown (fn [& _] (println "Rolling back transaction...")) (deftest "insert record" (assert (= 1 1))) (deftest "update record" (assert (= 2 2))) (deftest "delete record" (assert (= 3 3)))) ;; Group with test wrapper (for resource management) (defgroup browser-tests :test-wrapper (fn [test-fn & args] (let [browser (atom {:type "firefox"})] (println "Opening browser...") (try (apply test-fn args) (finally (println "Closing browser..."))))) (deftest "homepage loads" (assert true)) (deftest "login form works" (assert true))) ;; Combine multiple groups (defgroup all-tests database-tests browser-tests) ;; Run combined suite (tt/run-suite all-tests {:threads 4}) ``` -------------------------------- ### Test Run Configuration Options Source: https://github.com/weissjeffm/test.tree/blob/master/README.md Global configuration options passed to `test.tree/run` or `test.tree/run-suite` to control the test execution environment. ```APIDOC ## Test Run Options ### Description Configuration options for the entire test run, passed as an optional map to `test.tree/run` or `test.tree/run-suite`. ### Options * **:threads** - The number of concurrent threads to use for running tests. Limits the number of tests running simultaneously. * **:watchers** - A map where keys are watcher names and values are watch functions (compatible with `clojure.core/add-watch`). These functions receive events during the test run (e.g., test start, failure). * **:thread-wrapper** - (Advanced) A 1-argument function for thread-specific setup and teardown. The function performs setup, calls its argument (which runs the tests on that thread), and then performs teardown. ```clj (defn -main [ & args] (test.tree/run-suite all-calc-tests {:thread-runner (fn [run-tests] (open-my-browser "firefox") (run-tests) (close-my-browser)) :threads 5})) ``` ``` -------------------------------- ### Run Test Suite with test.tree Source: https://context7.com/weissjeffm/test.tree/llms.txt Use `run-suite` to execute all tests in a tree, generate JUnit and TestNG XML reports, and examine results. It blocks until completion. ```clojure (require '[test.tree :as tt]) (require '[test.tree.script :refer [deftest defgroup]]) ;; Define a simple test tree (defgroup my-tests (deftest "login test" (assert (= 1 1)) (deftest "create user" (assert (not (nil? "user-123"))))) ;; Run the test suite - blocks until all tests complete ;; Writes report.clj, testng-report.xml, and junitreport.xml (def results (tt/run-suite my-tests {:threads 4})) ;; Examine results (doseq [[test report] results] (println (:name test) "->" (-> report :report :result))) ;; Output: ;; login test -> :pass ;; create user -> :pass ``` -------------------------------- ### Define and Run All Calculator Tests Source: https://github.com/weissjeffm/test.tree/blob/master/README.org Groups multiple test suites (simple, scientific, trig) into a single 'all-tests' group and runs them. This allows for hierarchical test organization. ```clojure (defgroup all-tests simple-calc-tests scientific-calc-tests trig-calc-tests) (defn -main [ & args] (test.tree/run-suite all-calc-tests)) ``` -------------------------------- ### Define and Run a Test Suite in Clojure Source: https://github.com/weissjeffm/test.tree/blob/master/README.md This snippet demonstrates how to define a test group with nested tests, including data-driven tests, and then run the suite using test.tree. It requires importing 'calc.test' and 'test.tree.script'. ```clojure (require 'calc.test) (use 'test.tree.script) (defgroup simple-calc-tests :group-setup calc.test/open-app :group-teardown calc.test/close-app (deftest "enter numbers" (calc.test/enter-number 123) (assert (= (calc.test/current-display) "123")) (deftest "clear display" (calc.test/enter-number 234) (calc.test/clear-display) (assert (= (calc.test/current-display) "")) (deftest "add numbers" :data-driven true calc.test/add [[[1 1] 2] [[2 2] 4] [[1 -1] 0] [[1 2 3 4] 10] [[1.23 4.56] 5.79]])))) (defn -main [ & args] (test.tree/run-suite simple-calc-tests)) ``` -------------------------------- ### Define a Test with Optional Keys Source: https://github.com/weissjeffm/test.tree/blob/master/README.org Defines a test case with optional configuration keys like ':blockers' and ':description'. Use ':blockers' to skip tests conditionally and ':description' for reporting. ```clojure (deftest "my test" :blockers (constantly ["this test is currently disabled"]) :description "Runs foobar widget tests." (my-step1) (my-step2)) ``` -------------------------------- ### deftest - Define Individual Tests Source: https://context7.com/weissjeffm/test.tree/llms.txt The `deftest` macro creates test nodes with a name, optional configuration keywords, and test steps. Tests can be nested to create parent-child dependencies—child tests only run if their parent passes. ```APIDOC ## deftest - Define Individual Tests ### Description Creates test nodes with a name, optional configuration keywords, and test steps. Supports nesting for parent-child dependencies where child tests only run if their parent passes. ### Method `test.tree.script/deftest` (macro) ### Endpoint N/A (Macro for defining tests) ### Parameters #### Arguments - **name** (string) - Required - The name of the test. - **&body** - Required - The body of the test, containing steps and assertions. #### Options (Keywords within the body) - **:description** (string) - Optional - A detailed description of the test. - **:always-run** (boolean) - Optional - If true, the test runs even if its parent fails. - **:blockers** (vector of strings) - Optional - A list of conditions or reasons why the test might be skipped. ### Request Example ```clojure (require '[test.tree.script :refer [deftest defgroup]]) ;; Simple test with steps (deftest "verify addition" (let [result (+ 2 2)] (assert (= result 4) "2 + 2 should equal 4"))) ;; Test with options (deftest "verify multiplication" :description "Tests basic multiplication operations" :always-run true ;; Run even if parent fails (assert (= (* 3 4) 12))) ;; Nested tests - child only runs if parent passes (deftest "user login" (println "Logging in user...") (assert true) (deftest "user dashboard access" (println "Accessing dashboard...") (assert true) (deftest "user profile update" (println "Updating profile...") (assert true)))) ;; Test with blockers (conditionally skip) (deftest "feature requiring premium" :blockers ["Premium feature not available in test environment"] (println "This test will be skipped")) ``` ### Response N/A (This is a definition macro, it does not return a value in the traditional sense but defines a test node within the test tree.) ``` -------------------------------- ### Wrap tests with resources Source: https://github.com/weissjeffm/test.tree/blob/master/README.md Use :test-wrapper to manage resource lifecycle around test execution steps. ```clojure (defgroup recorded-tests :test-wrapper (fn [f & args] (let [rec (calc.test/new-screen-recorder)] (.start rec) (apply f args) (.stop rec))) (deftest ... ) (deftest ... ) ... ) ``` -------------------------------- ### Define a test with blockers and description Source: https://github.com/weissjeffm/test.tree/blob/master/README.md Use the :blockers and :description keys within a deftest to manage test execution status and reporting. ```clojure (deftest "my test" :blockers ["this test is currently disabled"] :description "Runs foobar widget tests." (my-step1) (my-step2)) ``` -------------------------------- ### Data-Driven Testing with Static Data Source: https://context7.com/weissjeffm/test.tree/llms.txt Implement data-driven tests by defining a test function and providing static input data rows using `:data-driven true`. ```clojure (require '[test.tree.script :refer [deftest defgroup runtime-data]]) (require '[test.tree :as tt]) ;; Define a test function that takes parameters (defn verify-addition [inputs expected] (let [result (apply + inputs)] (assert (= result expected) (format "Expected %s but got %s" expected result)))) ;; Data-driven test with static data (defgroup math-tests (deftest "addition tests" :data-driven true verify-addition [[[1 1] 2] [[2 2] 4] [[1 2 3] 6] [[10 -5] 5] [[0 0 0] 0]])) ;; Data-driven with runtime-generated data (evaluated at test execution time) (defgroup dynamic-tests (deftest "timestamp tests" :data-driven true (fn [timestamp] (assert (> timestamp 0) "Timestamp should be positive")) (runtime-data [(System/currentTimeMillis)] [(System/currentTimeMillis)]))) (tt/run-suite math-tests) ``` -------------------------------- ### run - Execute Tests Asynchronously Source: https://context7.com/weissjeffm/test.tree/llms.txt The `run` function executes tests in parallel without blocking. It returns a vector containing the thread pool and a reference to the reports, allowing you to monitor test progress in real-time. ```APIDOC ## run - Execute Tests Asynchronously ### Description Executes tests in parallel without blocking. Returns a vector containing the thread pool and a reference to the reports, allowing real-time progress monitoring. ### Method `clojure.core/->` (function call) ### Endpoint N/A (Library function) ### Parameters #### Arguments - **test-tree** (map or vector) - Required - The test tree structure to execute. - **options** (map) - Optional - Configuration options for test execution. - **:threads** (integer) - Number of threads to use for parallel execution. - **:watchers** (map) - A map of watchers to apply during test execution. - **:logger** (function) - A function to log test progress (e.g., `watcher/stdout-log-watcher`). ### Request Example ```clojure (require '[test.tree :as tt]) (require '[test.tree.watcher :as watcher]) (def my-tree {:name "root test" :steps (fn [] (println "root passed")) :more [{:name "child test" :steps (fn [] (println "child passed"))}]}) ;; Run tests asynchronously with watchers (let [[threads reports] (tt/run my-tree {:threads 2 :watchers {:logger watcher/stdout-log-watcher}})] ;; Do other work while tests run... (println "Tests are running in background") ;; Wait for completion when ready (tt/wait-for-all-test-results threads reports) ;; Access final results (println "Total tests:" (count @reports))) ``` ### Response #### Success Response (200) - **threads** (vector) - A vector containing the thread pool used for execution. - **reports** (atom) - An atom containing the test reports, which can be dereferenced to access progress and final results. #### Response Example ```clojure ;; Output from the example: ;; Tests are running in background ;; root test started ;; root test passed ;; child test started ;; child test passed ;; Total tests: 2 ``` ``` -------------------------------- ### Execute Tests Asynchronously with test.tree Source: https://context7.com/weissjeffm/test.tree/llms.txt Use `run` to execute tests in parallel without blocking. It returns a thread pool and report reference for real-time monitoring and later retrieval. ```clojure (require '[test.tree :as tt]) (require '[test.tree.watcher :as watcher]) (def my-tree {:name "root test" :steps (fn [] (println "root passed")) :more [{:name "child test" :steps (fn [] (println "child passed"))}]}) ;; Run tests asynchronously with watchers (let [[threads reports] (tt/run my-tree {:threads 2 :watchers {:logger watcher/stdout-log-watcher}})] ;; Do other work while tests run... (println "Tests are running in background") ;; Wait for completion when ready (tt/wait-for-all-test-results threads reports) ;; Access final results (println "Total tests:" (count @reports))) ``` -------------------------------- ### Define Individual Tests with deftest Source: https://context7.com/weissjeffm/test.tree/llms.txt The `deftest` macro defines test nodes. Tests can be nested, creating parent-child dependencies where children only run if their parent passes. Supports options like `:description` and `:always-run`. ```clojure (require '[test.tree.script :refer [deftest defgroup]]) ;; Simple test with steps (deftest "verify addition" (let [result (+ 2 2)] (assert (= result 4) "2 + 2 should equal 4"))) ;; Test with options (deftest "verify multiplication" :description "Tests basic multiplication operations" :always-run true ;; Run even if parent fails (assert (= (* 3 4) 12))) ;; Nested tests - child only runs if parent passes (deftest "user login" (println "Logging in user...") (assert true) (deftest "user dashboard access" (println "Accessing dashboard...") (assert true) (deftest "user profile update" (println "Updating profile...") (assert true)))) ;; Test with blockers (conditionally skip) (deftest "feature requiring premium" :blockers ["Premium feature not available in test environment"] (println "This test will be skipped")) ``` -------------------------------- ### Test Definition Options Source: https://github.com/weissjeffm/test.tree/blob/master/README.md Options that can be placed within deftest or defgroup to configure individual test behavior and metadata. ```APIDOC ## Deftest/Defgroup Options ### Description Options that can be placed inside `deftest` or `defgroup` to configure test behavior and metadata. ### Options * **:blockers** - A list of items that might be blocking this test. If a test is failing and cannot be fixed, it can be blocked from running to avoid polluting test results. Can be a simple string or keyword, or an implementation of `test.tree.Blocker` protocol for dynamic blocking. ```clj (deftest "my test" :blockers ["this test is currently disabled"] :description "Runs foobar widget tests." (my-step1) (my-step2)) ``` Example with dynamic blocking: ```clj (extend-type my.bugtracker.Issue test.tree.Blocker (blocks [i _] (when (my.bugtracker/open? i) (list i)))) (deftest "my test" :blockers (list (my.bugtracker.Issue. "bugid654321")) (my-step1) (my-step2)) ``` * **:group-setup** - `defgroup` only. A no-arg function to run before any test in the group. * **:group-teardown** - `defgroup` only. A no-arg function to run after all tests in the group have completed. * **:test-setup** - `defgroup` only. A function that runs before each test in the group. It accepts a variable number of arguments, which can be the data for a data-driven test or nothing if the test is not data-driven. ```clj (defgroup calc-division-tests :test-setup (fn [& _] (calc.test/clear-display)) (deftest ... ) (deftest ... )) ``` * **:test-teardown** - `defgroup` only. Similar to `test-setup`, but runs *after* each test, even if the test fails. * **:test-wrapper** - `defgroup` only. A function that wraps the execution of a test. It takes the test function and its arguments. It performs setup, calls the test function, and then performs teardown. ```clj (defgroup recorded-tests :test-wrapper (fn [f & args] (let [rec (calc.test/new-screen-recorder)] (.start rec) (apply f args) (.stop rec))) (deftest ... ) (deftest ... )) ``` * **:always-run** - If set to true, this test will run even if its parent did not pass. It is guaranteed to run after its parent. Use with caution. * **:description** - A detailed description of the test, used for inclusion in reports. ``` -------------------------------- ### Implement dynamic test blocking Source: https://github.com/weissjeffm/test.tree/blob/master/README.md Extend the test.tree.Blocker protocol to conditionally block tests based on external state like bug tracker issues. ```clojure (extend-type my.bugtracker.Issue test.tree.Blocker (blocks [i _] (when (my.bugtracker/open? i) (list i))) (deftest "my test" :blockers (list (my.bugtracker.Issue. "bugid654321")) (my-step1) (my-step2)) ``` -------------------------------- ### Configure Test Watchers in Clojure Source: https://context7.com/weissjeffm/test.tree/llms.txt Define custom callbacks for test lifecycle events like failures or status changes to enable logging and notifications. ```clojure (require '[test.tree :as tt]) (require '[test.tree.watcher :as watcher]) (require '[test.tree.script :refer [deftest defgroup]]) ;; Built-in stdout watcher (def options-with-stdout {:threads 2 :watchers {:stdout watcher/stdout-log-watcher}}) ;; Custom failure notification watcher (def failure-notifier (watcher/on-fail (fn [test report] (println (format "ALERT: Test '%s' failed!" (:name test))) (println "Error:" (-> report :report :error :message))))) ;; Custom status watcher (fires when test reaches specific status) (def queued-watcher (watcher/status-watcher :queued (fn [test report] (println (format "Test '%s' queued for execution" (:name test)))))) (def running-watcher (watcher/status-watcher :running (fn [test report] (println (format "Test '%s' started running" (:name test)))))) ;; Combine multiple watchers (defgroup monitored-tests (deftest "test one" (assert true)) (deftest "test two" (assert false)) ;; Will fail (deftest "test three" (assert true))) (tt/run-suite monitored-tests {:threads 2 :watchers {:stdout watcher/stdout-log-watcher :failures failure-notifier :queued queued-watcher :running running-watcher}}) ``` -------------------------------- ### Generate and Analyze Test Reports Source: https://context7.com/weissjeffm/test.tree/llms.txt Analyze test results programmatically or export them to standard XML formats like JUnit and TestNG. ```clojure (require '[test.tree :as tt]) (require '[test.tree.reporter :as reporter]) (require '[test.tree.script :refer [deftest defgroup]]) (defgroup sample-tests (deftest "passing test" (assert true)) (deftest "failing test" (assert false)) (deftest "skipped test" :blockers ["Intentionally skipped"] (assert true))) ;; Run tests and get reports (def results (tt/run-suite sample-tests)) ;; Analyze results using reporter functions (doseq [[test _] results] (let [entry [test (results test)]] (println (:name test)) (println " Passed?" (reporter/passed? entry)) (println " Failed?" (reporter/failed? entry)) (println " Skipped?" (reporter/skipped? entry)) (println " Execution time:" (reporter/execution-time entry) "seconds") (when (reporter/failed? entry) (println " Error:" (-> entry reporter/error :message))))) ;; Generate JUnit XML report manually (let [junit-xml (reporter/junit-report results)] (spit "custom-junit.xml" junit-xml)) ;; Generate TestNG XML report manually (let [testng-xml (reporter/testng-report results)] (spit "custom-testng.xml" testng-xml)) ;; Get total execution time (println "Total time:" (reporter/total-time results) "seconds") ;; Get blocker frequency report (println "Blockers:" (reporter/blocker-report results)) ``` -------------------------------- ### Manipulate Test Trees with Builder Functions Source: https://context7.com/weissjeffm/test.tree/llms.txt Use builder functions to filter, transform, and compose test structures, including adding setup/teardown logic and dependency chains. ```clojure (require '[test.tree.builder :as builder]) (require '[test.tree.script :refer [deftest defgroup]]) (require '[test.tree :as tt]) ;; Filter tests by name (def all-tests [{:name "login" :steps (fn [] (assert true))} {:name "logout" :steps (fn [] (assert true))} {:name "signup" :steps (fn [] (assert true))}]) ;; Create predicate for filtering (def login-tests? (builder/named? #{"login" "logout"})) ;; Add setup/teardown to specific tests (defgroup base-tests (deftest "test A" (assert true)) (deftest "test B" (assert true))) ;; Run function before tests matching predicate (def enhanced-tests (-> base-tests (builder/run-before (constantly true) (fn [] (println "Setup for test"))) (builder/run-after (constantly true) (fn [] (println "Teardown for test"))))) ;; Create dependency chain from list of tests (def ordered-tests (builder/dep-chain [{:name "step 1" :steps (fn [] (println "First"))} {:name "step 2" :steps (fn [] (println "Second"))} {:name "step 3" :steps (fn [] (println "Third"))}])) ;; Run a test before all others in a tree (def with-global-setup (builder/before-all {:name "Global Setup" :configuration true :steps (fn [] (println "Global init"))} base-tests)) ;; Run a test after all others complete (def with-global-teardown (builder/after-all {:name "Global Cleanup" :configuration true :steps (fn [] (println "Global cleanup"))} base-tests)) (tt/run-suite with-global-setup) ``` -------------------------------- ### Define Test with Dynamic Blockers Source: https://github.com/weissjeffm/test.tree/blob/master/README.org Defines a test that can be dynamically skipped at runtime based on a condition checked against a bug tracker. The function returns a list of reasons if the bug is still open. ```clojure (deftest "my test" :blockers (fn [_] (my.bugtracker.client/is-bug-still-open? "bug654321")) (my-step1) (my-step2)) ``` -------------------------------- ### Conditional Test Skipping with Blocker Protocol Source: https://context7.com/weissjeffm/test.tree/llms.txt Use the `Blocker` protocol to dynamically skip tests based on external conditions like bug tracker status or feature flags. Extend `Blocker` for custom logic. ```clojure (require '[test.tree :as tt]) (require '[test.tree.script :refer [deftest defgroup]]) (require '[test.tree.builder :as builder]) ;; Simple string blockers always block (deftest "blocked test" :blockers ["Bug #12345 - Feature not implemented"] (assert false "This never runs")) ;; Extend Blocker protocol for custom logic (defrecord BugTracker [bug-id]) (extend-type BugTracker tt/Blocker (blockers [bug state] ;; Return list of blockers if bug is open, empty list if fixed (let [bug-status (get {"BUG-123" :open "BUG-456" :fixed} (:bug-id bug) :unknown)] (if (= bug-status :open) [(str "Blocked by " (:bug-id bug))] [])))) (defgroup feature-tests (deftest "feature with known bug" :blockers [(->BugTracker "BUG-123")] ;; Will be skipped (bug is open) (assert true)) (deftest "feature with fixed bug" :blockers [(->BugTracker "BUG-456")] ;; Will run (bug is fixed) (assert true))) ;; Block based on other test results (defgroup dependent-tests (deftest "prerequisite test" (assert true)) (deftest "dependent test" :blockers [(builder/blocking-tests "prerequisite test")] (assert true))) (tt/run-suite feature-tests) ``` -------------------------------- ### Configure Sequential Test Execution Source: https://context7.com/weissjeffm/test.tree/llms.txt Disable parallel execution by setting the number of threads to 1, ensuring tests run sequentially. This is useful for debugging or when tests have inherent sequential dependencies. ```clojure ;; Sequential execution (disable parallelism) (tt/run-suite parallel-tests {:threads 1}) ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.