From e668d83b1806d31784e3bc6c82e75611ca243fd6 Mon Sep 17 00:00:00 2001 From: Joshua Smock Date: Fri, 26 May 2023 14:00:36 +0200 Subject: [PATCH] Add docs about matchers and how to add a custom matcher - Update changelog (including previous missing `setup-mocks` fix) --- changelog.md | 13 +++++++++ docs/component-tests.md | 3 ++- docs/matchers.md | 58 +++++++++++++++++++++++++++++++++++++++++ readme.md | 1 + 4 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 docs/matchers.md diff --git a/changelog.md b/changelog.md index 487735e..ab30691 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,18 @@ # Changelog +# Next + +## Features +- [Allow users to define their own matchers.](https://github.com/pitch-io/cljest/pull/27) + +## Improvements +- [Allow aliases to be defined in `cljest.edn` so that Jest can use it when getting the classpath.](https://github.com/pitch-io/cljest/pull/27) + +## Bugfixes +- [Always reinstantiate mocks for each test case when using `setup-mocks`.](https://github.com/pitch-io/cljest/pull/28) +- [Fix matcher negation.](https://github.com/pitch-io/cljest/pull/27) + + # 1.0.0 ## Features diff --git a/docs/component-tests.md b/docs/component-tests.md index 3d9f1b9..f94f6ec 100644 --- a/docs/component-tests.md +++ b/docs/component-tests.md @@ -87,8 +87,9 @@ Okay, how do we test it? To test it, we need to render our component and simulat Looking at the above, you'll notice a few things: - We're rendering our component, `main/the-bakery`, very similarly to how we do in our normal code, and you don't need to keep a reference to it later. Instead, `h.dom/get-by` (and other query functions) use the ["screen"](https://testing-library.com/docs/queries/about#screen), the `document.body`, when looking for elements. -- We queried by text rather than a testing ID. Whenever possible, it's best to query for elements by their ARIA role, text, or something visible or spec defined, and query by the test ID as a last resort. https://testing-library.com/docs/queries/about#priority +- We queried by text rather than a testing ID. Whenever possible, it's best to query for elements by their ARIA role, text, or something visible or spec defined, and query by the test ID as a last resort. For some details about when to use which queries, see the [`testing-library` query priority docs](https://testing-library.com/docs/queries/about#priority). - We're testing the component from the end user's perspective. We don't know that internally it's using `use-state`, and for all we know, it could be using `re-frame` or another state management library. +- We're using a matcher to assert that the element is visible, which is coming from `cljest.matchers`. For more details about matchers, please see the [`cljest.matchers` namespace](https://github.com/pitch-io/cljest/blob/master/cljest/src/cljest/matchers.cljs) and the [matchers docs](./matchers.md). ## Going further - more cookies!! diff --git a/docs/matchers.md b/docs/matchers.md new file mode 100644 index 0000000..ed24c82 --- /dev/null +++ b/docs/matchers.md @@ -0,0 +1,58 @@ +# Matchers + +[Matchers are the way Jest deals with assertions](https://jestjs.io/docs/using-matchers), and are the functions that are defined on `expect`: + +```js +// `toBe` is the matcher here +expect(1).toBe(1); +``` + +`cljest` has some built-in matchers, primarily coming from [`jest-dom`](https://github.com/testing-library/jest-dom), and is extendable, allowing for you to define your own custom matchers in your code without needing to include them in `cljest` directly. + +# How do I use matchers? + +Matchers act just like another assertion: you wrap it in `is` and Jest will assert when it's called: + +```clj +(require '[cljest.core :refer [it is]] + '[cljest.helpers.dom :as h.dom] + '[cljest.matchers :as m] + '[uix.core :refer [$ defui]]) + +(defui my-cool-component + [] + ($ :div.blue "hello world")) + +(it "should have the `blue` class when initially rendered" + (h.dom/render ($ my-cool-component)) + (is (m/has-class? (h.dom/get-by :text "hello world") "blue"))) +``` + +If you don't wrap your matcher in `is`, you'll get an error; matchers must be wrapped in `is` to work. + +## Negation + +Matchers can also be negated using `not`: + +```clj +(it "should not have the `red` class when initially rendered" + (h.dom/render ($ my-cool-component)) + (is (not (m/has-class? (h.dom/get-by :text "hello world") "red")))) +``` + +# Built-in matchers + +By default, `cljest` includes matchers from [`jest-dom`](https://github.com/testing-library/jest-dom), such as `toBeVisible`, `toHaveClass`, `toBeValid`, as well as a few assertions for `spy` calls like `called-with?`. These matchers live in [`cljest.matchers`](https://github.com/pitch-io/cljest/blob/master/cljest/src/cljest/matchers.cljs), and so for more details about which matchers are available, please look at the defined matchers in the `cljest.matchers` namespace. + +# How do I make my own matcher? + +In the event there's a matcher you'd like to use that's not included in `cljest`, you can use the macro `cljest.matcher/defmatcher` to define your matcher. This macro is like `def`, and takes the symbol (like `has-class?`) and the underlying matcher name (like `toHaveClass`): + +```clj +(ns app.custom-matchers + (:require-macros [cljest.matchers :refer [defmatcher]])) + +(defmatcher has-class? "toHaveClass") +``` + +That's all you need to do! The rest is handled internally, including support negation, and basically this macro defines a function that has some metadata that's used during compilation to treat it as a matcher rather than a non-matcher assertion inside of `is`. diff --git a/readme.md b/readme.md index fc37d1a..42cf784 100644 --- a/readme.md +++ b/readme.md @@ -27,6 +27,7 @@ For more details, as well as details about getting started and configuration, pl [Migrating from `cljs.test` to `cljest` and differences](./docs/migrating.md)
[Unit tests](./docs/unit-tests.md)
[Component tests](./docs/component-tests.md)
+[Matchers](./docs/matchers.md)
[Mocking](./docs/mocking.md)
[Async code](./docs/async.md)
[General API docs](./docs/api.md)