Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.cpcache
.clj-kondo/.cache
*.jar
cljs-test-runner-out
44 changes: 44 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ and command-line tools.
Works with Clojure 1.8 and later. Spec expectations are only available on
Clojure 1.9 and later.

Works in self-hosted Clojurescript (specifically,
[`planck`](https://planck-repl.org)). See
[Getting Started with Clojurescript](/doc/getting-started-cljs.md) for details.

You can either use `deftest` from `clojure.test`, or `defexpect` from
this library to wrap your tests.

Expand Down Expand Up @@ -244,6 +248,46 @@ do
done
```

### Clojurescript testing

The Clojurescript version requires self-hosted Clojurescript (specifically,
[`planck`](https://planck-repl.org)). Once you have `planck -h` working,
you can run the Clojurescript tests with:

```clojure
clojure -A:cljs-runner -e :negative
```
You can run the negative tests as well if you modify one line of `test.cljc`,
see the comments below the line containing `(def humane-test-output?`.

#### Clojurescript REPL

It can be handy to try things in a REPL. You can run a REPL for Clojurescript
by doing:
```clojure
$ planck --compile-opts planckopts.edn -c `clj -A:humane -Spath` -r
ClojureScript 1.10.520
cljs.user=> (require '[expectations.clojure.test :refer-macros [defexpect expect]])
nil
cljs.user=> (defexpect a (expect number? 1))
#'cljs.user/a
cljs.user=> (a)
nil
cljs.user=> (defexpect a (expect number? :b))
#'cljs.user/a
cljs.user=> (a)

FAIL in (a) (run_block@file:44:173)


expected: (=? number? :b)
actual: (not (number? :b))
nil
cljs.user=>
```
This will set you up with `defexpect` and `expect`. Add others as required.


## License & Copyright

Copyright © 2018-2020 Sean Corfield, all rights reserved.
Expand Down
9 changes: 8 additions & 1 deletion deps.edn
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,11 @@
{:git/url "https://github.com/cognitect-labs/test-runner"
:sha "f7ef16dc3b8332b0d77bc0274578ad5270fbfedd"}}
:main-opts ["-m" "cognitect.test-runner"
"-d" "test"]}}}
"-d" "test"]}
:cljdoc {:extra-deps {planck {:mvn/version "2.23.0"}}}
:cljs-runner
{:extra-deps {olical/cljs-test-runner {:mvn/version "3.7.0"},
pjstadig/humane-test-output {:mvn/version "0.10.0"}},
:extra-paths ["src" "test" "cljs-test-runner-out/gen"],
:main-opts ["-m" "cljs-test-runner.main" "--doo-opts"
"dooopts.edn" "-x" "planck"]}}}
1 change: 1 addition & 0 deletions doc/cljdoc.edn
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{:cljdoc.doc/tree [["Readme" {:file "README.md"}]
["Changes" {:file "CHANGELOG.md"}]
["Getting Started" {:file "doc/getting-started.md"}]
["Getting Started in Clojurescript" {:file "doc/getting-started-cljs.md"}]
["Collections" {:file "doc/collections.md"}]
["Useful Predicates" {:file "doc/useful-predicates.md"}]
["Expecting More" {:file "doc/more.md"}]
Expand Down
197 changes: 197 additions & 0 deletions doc/getting-started-cljs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
# Getting Started with expectations/clojure-test using Clojurescript

You can use `expectations/clojure-test` to run tests in both Clojure
and Clojurescript. Many tests will work without changes in both
Clojure and Clojurescript, though of course some will require
changes for the different environments. This section describes how
to use `expectations/clojure-test` in Clojurescript and the differences
from using it in Clojure -- see the other sections for details of how
to use it in Clojure for a complete picture.


## Installation

In order to run `expectations/clojure-test` with Clojurescript, you
will use `olical/cljs-test-runner` and the Clojure tool `clj`.

Your `deps.edn` should include this information:

```clojure
{:aliases {:cljs-runner
{:extra-deps {expectations/cljc-test {:mvn/version "1.4.1"},
olical/cljs-test-runner {:mvn/version "3.7.0"},
pjstadig/humane-test-output {:mvn/version "0.10.0"}},
:extra-paths ["src" "test" "cljs-test-runner-out/gen"],
:main-opts ["-m" "cljs-test-runner.main" "--doo-opts"
"dooopts.edn" "-x" "planck"]}}}
```

You will need two small `.edn` files in your project:

`dooopts.edn`:
```clojure
{:paths {:planck "planck --compile-opts planckopts.edn"}}
```

`planckopts.edn`:
```clojure
{:warnings {:private-var-access false}}
```

To run the tests, you run:

```
clj -A:cljs-runner
```

These tests will take a good while longer to run than the same tests
in Clojure, so if you don't get any output for a while, that is not
necessarily a bad thing.

### Requirements

The Clojurescript version of `expectations/clojure-test` works (at present)
only with a specific implementation of self-hosted Clojurescript:
[`planck`](https://planck-repl.org). You will have to install `planck`
yourself in order to use `expectations/clojure-test` with Clojurescript.

You will have to get `planck -h` to work locally. See
[here](https://planck-repl.org) for instructions on how to install
`planck` on a variety of systems. Planck `2.24.0` or later is required.

### Humane Test Output

The use of Paul Stadig's
[Humane Test Output](https://github.com/pjstadig/humane-test-output), is
optional for the Clojure version of `expectations/clojure-test` but it is
required for the Clojurescript version of `expectations/clojure-test`.

## The Basics

This example is the Clojurescript version of the quick comparison provided
for the Clojure version of `expectations/clojure-test`, and provides a quick
comparison with `clojure.test` (the tests match those in the [`clojure.test`
documentation](http://clojure.github.io/clojure/clojure.test-api.html)):

```clojure
(require '[expectations.clojure.test :refer [defexpect expect expecting]])

(defexpect simple-test ; (deftest simple-test
(expect 4 (+ 2 2)) ; (is (= 4 (+ 2 2)))
(expect number? 256) ; (is (instance? Long 256))
(expect (.startsWith "abcde" "ab")) ; (is (.startsWith "abcde" "ab"))
(expect ##Inf (/ 1 0)) ; (is (thrown? ArithmeticException (/ 1 0)))
(expecting "Arithmetic" ; (testing "Arithmetic"
(expecting "with positive integers" ; (testing "with positive integers"
(expect 5 (+ 2 2)) ; (is (= 4 (+ 2 2)))
(expect 7 (+ 3 4))) ; (is (= 7 (+ 3 4))))
(expecting "with negative integers" ; (testing "with negative integers"
(expect -4 (+ -2 -2)) ; (is (= -4 (+ -2 -2)))
(expect -1 (+ 3 -4))))) ; (is (= -1 (+ 3 -4))))))
```

The third example could also be written as follows, since `expect`
allows an arbitrary predicate in the "expected" position:

```clojure
(expect #(.startsWith % "ab") "abcde")
```

Or like this, since `expect` allows a regular expression in the "expected" position:

```clojure
(expect #"^ab" "abcde")
```

Both of these more accurately reflect an expectation on the actual
value `"abcde"`, that the string begins with `"ab"`, than the `is`
equivalent which has the actual value embedded in the test expression.
Separating the "expectation" (value or predicate) from the "actual"
expression being tested often makes the test much clearer.

## Differences from the Clojure version of `expectations/clojure-test`

Here is the list of features from Expectations supported by the
Clojure version of `expectations.clojure.test` where there are
differences in the Clojurescript implementation.

### * Class test
Classes are different in Clojurescript.

Classes are all different in Clojurescript, and in some cases things
that would be a class in Clojure are different in Clojurescript. For
instance, lists are a class:
```clojure
(defexpect class-test cljs.core/List '(a b c))
```
and this test passes. Strings, however, don't have an easily
discoverable type or class, and are better handled with a predicate:
```clojure
(defexpect string-class-test string? "abc")
```
In general, the classes in Clojurescript will not be the same as
the classes in Clojure. You can do this to write a test that
will work in both environments:
```clojure
(defexpect both-class-test (expect (= (type "abc") (type "def"))))
```
but you cannot write this:
```
(defexpect bad-both-class-test (type "abc") (type "def"))
```
because `(type "abc")` yields something that tests positive as a
`fn?`, causing expectations to think it is a predicate. Which,
as it happens, it is not.

### * Exception test

Exceptions are very different in Clojurescript from Clojure.

The Clojure example:
```clojure
(defexpect divide-by-zero ArithmeticException (/ 12 0))
```
doesn't even throw an exception -- it returns `##Inf`.
You can do this for that situation:
```clojure
(defexpect divide-by-zero ##Inf (/ 12 0))
```
but be careful putting `##Inf` in a reader conditional, as some versions of
Clojure don't handle that well. But all of this is a bit off-topic,
as we are discussing exceptions.

Exceptions certainly exist and can be thrown. You can throw pretty
much anything in Javascript. There is no `Throwable` class in
Clojurecript to distinguish things that can be thrown from anything
else. The only exception supported in `expectations/clojure-test`
in Clojurescript is where the exception is: `js/Error`. For example:
```clojure
(defexpect exception js/Error (count 5))
```
will pass, because `(count 5)` throws `js/Error`.

### * `with-test`
There is no `with-test` in `cljs.test`, so it is not available in
`expectations/clojure-test`.

### * Specs
Specs are always supported, and work equivalently to Clojure.

# Useful Additional Information

The end of the Clojure [Getting Started](/doc/getting-started.md) provides
additional information on how to use `expectations/clojure-test`, and most
of the information is directly applicable to using `expectations/clojure-test`
in Clojurescript as well.

# Further Reading

Expectations provides a lot more:

* [Useful Predicates](/doc/useful-predicates.md)
* [Collections](/doc/collections.md)
* [Expecting More](/doc/more.md)
* [Expecting Side Effects](/doc/side-effects.md)
* [Fixtures & Focused Test Execution](/doc/fixtures-focus.md)


1 change: 1 addition & 0 deletions dooopts.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{:debug false :paths {:planck "planck --compile-opts planckopts.edn"}}
1 change: 1 addition & 0 deletions planckopts.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{:warnings {:private-var-access false}}
16 changes: 14 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>expectations</groupId>
<artifactId>clojure-test</artifactId>
<version>1.2.1</version>
<artifactId>cljc-test</artifactId>
<version>1.3.1</version>
<name>exp-clojure-test</name>
<description>A clojure.test-compatible version of the classic Expectations testing library.</description>
<url>https://github.com/clojure-expectations/clojure-test</url>
Expand All @@ -30,6 +30,18 @@
<artifactId>clojure</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>pjstadig</groupId>
<artifactId>humane-test-output</artifactId>
<version>0.10.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>planck</groupId>
<artifactId>planck</artifactId>
<version>2.23.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<sourceDirectory>src</sourceDirectory>
Expand Down
Loading