Add cljs-test to test-runner via browser/html

- standardised test namespaces: renamed to use -test suffix and moved to eliminate redundant /test folder
- added cljs-test based tests via browser/html. These mimic original karma tests.
   NOTE: previous lein aliases `once` and `auto` have been replaced by `test-once` , `test-auto` & `karma-once`
- update karma.conf & circle.yml
- updated CHANGES.md & CONTRIBUTING.md
This commit is contained in:
hipitihop 2016-07-14 11:21:12 +10:00
parent b75ec509bb
commit a1314eb6c3
11 changed files with 280 additions and 98 deletions

View File

@ -1,87 +1,87 @@
## 0.8.0 (2016.07.XX)
Staying on the leading edge of new buzzwords is obviously critical for any framework. Angular's terrifying faceplant
is a sobering reminder to us all. With this release, re-frame's already impressive buzzword muscles
bulge further with new walnuts like "effects", "coeffects", and "de-duplicated signal graph". Yeah, I know, right?
Staying on the leading edge of new buzzwords is obviously critical for any framework. Angular's terrifying faceplant
is a sobering reminder to us all. With this release, re-frame's already impressive buzzword muscles
bulge further with new walnuts like "effects", "coeffects", and "de-duplicated signal graph". Yeah, I know, right?
Some may even find these new features useful.
Headline:
- re-frame subscriptions are now de-duplicated. As a result,
- re-frame subscriptions are now de-duplicated. As a result,
many Signal graphs will be more
efficient. The new behaviour better matches programmer intuitions about what "should" happen.
efficient. The new behaviour better matches programmer intuitions about what "should" happen.
*Explanation*
Each subscription causes a handler to execute, producing
a reactive stream of updates. Two calls to `(subscribe [:some :query])` results in two copies of the same
subscription handler running, each delivering a stream of updates. Now, if these two subscriptions
were running at the same time, this would be inefficient. Both handlers would be
doing the same computations and delivering the same stream of updates. Unnecessary, duplicate work.
Starting with this version, this sort of duplication has been eliminated. Two, or more, concurrent
subscriptions for the same query will now source reactive updates from the one executing handler.
Starting with this version, this sort of duplication has been eliminated. Two, or more, concurrent
subscriptions for the same query will now source reactive updates from the one executing handler.
So, how do we know if two subscriptions are "the same"? Answer: two subscriptions
are the same if their query vectors test `=` to each other.
So, these two subscriptions are *not* "the same": `[:some-event 42]` `[:some-event "blah"]`. Even
though they involve the same event id, `:some-event`, the query vectors do not test `=`.
- added a new subscription handler registration function called `re-frame.core/def-sub`. It is an
So, these two subscriptions are *not* "the same": `[:some-event 42]` `[:some-event "blah"]`. Even
though they involve the same event id, `:some-event`, the query vectors do not test `=`.
- added a new subscription handler registration function called `re-frame.core/def-sub`. It is an
alternative to `re-frame.core/register-sub` (now renamed to `re-frame.core/def-sub-raw`).
`def-sub` is significantly easier to use and understand,
while often also being more performant. The design has really fallen out nicely and we're
while often also being more performant. The design has really fallen out nicely and we're
delighted with it.
With `def-sub`, you no longer need to use `reaction` explicitly. Subscription handlers are now pure
which makes them easier to understand and test etc. Plus, as you'll see in the docs, there is some
gratuitous syntactic sugar.
The todomvc example is a tutorial on the subject:
The todomvc example is a tutorial on the subject:
https://github.com/Day8/re-frame/blob/master/examples/todomvc/src/todomvc/subs.cljs
- The API for the undo/redo features has been put into `re-frame.core`.
Detailed documentation is now available: https://github.com/Day8/re-frame/wiki/Undo-&-Redo
While undo and redo has been a part of re-frame from the beginning, the feature has been hidden
and not documented, so it is nice to see it given proper API status.
- The API for the undo/redo features has been put into `re-frame.core`.
Detailed documentation is now available: https://github.com/Day8/re-frame/wiki/Undo-&-Redo
While undo and redo has been a part of re-frame from the beginning, the feature has been hidden
and not documented, so it is nice to see it given proper API status.
Plus, this release has [a couple of enhancements](https://github.com/Day8/re-frame/wiki/Undo-&-Redo#harvesting-and-re-instating)
over that which previously existed previously.
- there's now two kinds of event handlers: pure and effectful. XXX
over that which previously existed previously.
- there's now two kinds of event handlers: pure and effectful. XXX
For description see: https://github.com/Day8/re-frame/wiki/Effectful-Event-Handlers
- taking advantage of the new effectful event handlers, there's now a new library
which makes it easy to XXXX
Breaking:
- requires Reagent >= v0.6.0
- `re-frame.core/register-handler` has been renamed `re-frame.core/def-event`. (There's now
two kinds of event-handlers, pure and effectful. Event handlers of the 2nd, new kind
should be registered via the new function `re-frame.core/def-event-fx`)
- `re-frame.core/register-sub` has been renamed `re-frame.core/def-sub-raw`. This is to indicate that
this kind of registration is now considered the low level, close to the metal way to
- requires Reagent >= v0.6.0
- `re-frame.core/register-handler` has been renamed `re-frame.core/def-event`. (There's now
two kinds of event-handlers, pure and effectful. Event handlers of the 2nd, new kind
should be registered via the new function `re-frame.core/def-event-fx`)
- `re-frame.core/register-sub` has been renamed `re-frame.core/def-sub-raw`. This is to indicate that
this kind of registration is now considered the low level, close to the metal way to
create subscriptions handlers. This release introduced `def-sub` which becomes the preferred way
to register subscription handlers.
- By default, re-frame uses `js/console` functions like `error` and `warn` when logging, but you can
supply alternative functions using `re-frame.core/set-loggers!`.
With this release, any alternatives you supply will be called with different parameters.
Previously loggers were called with a single `str` parameter but now they are expected to act
- By default, re-frame uses `js/console` functions like `error` and `warn` when logging, but you can
supply alternative functions using `re-frame.core/set-loggers!`.
With this release, any alternatives you supply will be called with different parameters.
Previously loggers were called with a single `str` parameter but now they are expected to act
like `console.log` itself and take variadic, non string params. Sorry to break things, but
we are trying to maximise use of cljs-devtools and information is lost when strings are
we are trying to maximise use of cljs-devtools and information is lost when strings are
output, instead of actual data.
Of course, you need only worry about this if you are using `re-frame.core/set-loggers!` to
hook in your own loggers. If you are, then, to transition, you'll need to tweak like this:
Of course, you need only worry about this if you are using `re-frame.core/set-loggers!` to
hook in your own loggers. If you are, then, to transition, you'll need to tweak like this:
```
;; your old log function might have looked like this. Single string parameter.
(defn my-logger [s] (do-something-with s))
(defn my-logger [s] (do-something-with s))
;; your new version will have variadic params, and turn them into a string
(defn my-logger [& args] (do-something-with (apply str args))
```
@ -92,10 +92,21 @@ Improvements
- XXX todomvc changed to use spec, instead of Schema
- Bug fix: `post-event-callbacks` were not called when `dispatch-sync` was called.
- added new API `re-frame.core/remove-post-event-callback`. See doc string.
- when an event-handler makes no change to `app-db`, the `debug` middleware now logs a
single line saying so, rather than a "group". Makes it slightly easier to grok
- added new API `re-frame.core/remove-post-event-callback`. See doc string.
- when an event-handler makes no change to `app-db`, the `debug` middleware now logs a
single line saying so, rather than a "group". Makes it slightly easier to grok
the absence of change.
- Standardised test namespaces: renamed to use -test suffix and moved to eliminate redundant /test folder
- Added cljs.test based tests via browser/html. These mimic original karma tests. NOTE: previous lein aliases `once` and `auto` have been replaced by `test-once` , `test-auto` & `karma-once` see [CONTRIBUTING.md](CONTRIBUTING.md)
####Other:####
- changed dev deps/plugins
<pre>
binaryage/devtools "0.7.2"
lein-npm "0.6.2"
lein-figwheel "0.5.4-7"
lein-shell "0.5.0" (added)
</pre>
## 0.7.0 (2016-03-14)

View File

@ -26,12 +26,21 @@ Use your best judgement on what is needed here.
## Running the tests
#### Via Browser/HTML
```sh
lein test-once # builds re-frame tests & opens browser on test/test.html
# or lein test-auto # then open a browser on test/test.html
# and refresh browser to rerun tests after each auto compile.
```
#### Via Karma
To run the tests, you must have recent versions of node, npm, Leiningen, and a C++ compiler toolchain installed. If you're on Linux or Mac OS X then you will be fine, if you're on Windows then you need to install Visual Studio Community Edition, and the C++ compiler dependencies.
```
lein deps # will run lein-npm and install Karma and other node dependencies. Only needed the first time.
lein once # or lein auto # to build re-frame
karma start # to run the tests with an auto watcher
```sh
lein deps # runs lein-npm, installs Karma & other node dependencies. Only needed the first time.
lein karma-once # to build re-frame tests
karma start # to run the tests with an auto watcher
```
## Pull requests for bugs

View File

@ -10,5 +10,5 @@ dependencies:
- node_modules
test:
override:
- lein once
- lein karma-once
- karma start --single-run --reporters junit,dots

View File

@ -1,6 +1,6 @@
module.exports = function (config) {
var root = 'run/compiled/test'; // same as :output-dir
var junitOutputDir = process.env.CIRCLE_TEST_REPORTS || "run/compiled/test/junit";
var root = 'run/compiled/karma/test'; // same as :output-dir
var junitOutputDir = process.env.CIRCLE_TEST_REPORTS || "run/compiled/karma/test/junit";
config.set({
frameworks: ['cljs-test'],
@ -11,7 +11,7 @@ module.exports = function (config) {
],
client: {
args: ['re_frame.test.runner.run']
args: ['re_frame.test_runner.run_karma']
},
// the default configuration

View File

@ -4,37 +4,52 @@
:license {:name "MIT"}
:dependencies [[org.clojure/clojure "1.8.0"]
[org.clojure/clojurescript "1.9.89"]
[reagent "0.6.0-rc"]]
[reagent "0.6.0-rc"]]
:profiles {:debug {:debug true}
:dev {:dependencies [[karma-reporter "0.3.0"]
[binaryage/devtools "0.7.0"]]
:plugins [[lein-cljsbuild "1.1.3"]
[lein-npm "0.6.1"]
[lein-figwheel "0.5.4-2"]]}}
:dev {:dependencies [[karma-reporter "0.3.0"]
[binaryage/devtools "0.7.2"]]
:plugins [[lein-cljsbuild "1.1.3"]
[lein-npm "0.6.2"]
[lein-figwheel "0.5.4-7"]
[lein-shell "0.5.0"]]}}
:clean-targets [:target-path
"run/compiled"]
:clean-targets [:target-path "run/compiled"]
:resource-paths ["run/resources"]
:jvm-opts ["-Xmx1g" "-XX:+UseConcMarkSweepGC"]
:source-paths ["src"]
:test-paths ["test"]
:source-paths ["src"]
:test-paths ["test"]
:shell {:commands {"open" {:windows ["cmd" "/c" "start"]
:macosx "open"
:linux "xdg-open"}}}
:deploy-repositories [["releases" :clojars {:sign-releases false}]
["snapshots" :clojars {:sign-releases false}]]
:npm {:dependencies [[karma "1.0.0"]
[karma-cljs-test "0.1.0"]
:npm {:dependencies [[karma "1.0.0"]
[karma-cljs-test "0.1.0"]
[karma-chrome-launcher "0.2.0"]
[karma-junit-reporter "0.3.8"]]}
[karma-junit-reporter "0.3.8"]]}
:cljsbuild {:builds [{:id "test"
:source-paths ["test" "src"]
:compiler {:output-to "run/compiled/test.js"
:source-map "run/compiled/test.js.map"
:output-dir "run/compiled/test"
:compiler {:output-to "run/compiled/browser/test.js"
:source-map true
:output-dir "run/compiled/browser/test"
:optimizations :none
:source-map-timestamp true
:pretty-print true}}
{:id "karma"
:source-paths ["test" "src"]
:compiler {:output-to "run/compiled/karma/test.js"
:source-map "run/compiled/karma/test.js.map"
:output-dir "run/compiled/karma/test"
:optimizations :whitespace
:main "re_frame.test_runner"
:pretty-print true}}]}
:aliases {"auto" ["do" "clean," "cljsbuild" "auto" "test,"]
"once" ["do" "clean," "cljsbuild" "once" "test,"] })
:aliases {"test-once" ["do" "clean," "cljsbuild" "once" "test," "shell" "open" "test/test.html"]
"test-auto" ["do" "clean," "cljsbuild" "auto" "test,"]
"karma-once" ["do" "clean," "cljsbuild" "once" "karma,"]})

View File

@ -1,4 +1,4 @@
(ns re-frame.test.middleware
(ns re-frame.middleware-test
(:require [cljs.test :refer-macros [is deftest]]
[reagent.ratom :refer [atom]]
[re-frame.middleware :as middleware]))

View File

@ -1,4 +1,4 @@
(ns re-frame.test.subs
(ns re-frame.subs-test
(:require [cljs.test :refer-macros [is deftest]]
[reagent.ratom :refer-macros [reaction]]
[re-frame.subs :as subs]

View File

@ -1,15 +0,0 @@
(ns re-frame.test.runner
(:require [jx.reporter.karma :as karma :include-macros true]
[re-frame.test.middleware]
[re-frame.test.undo]
[re-frame.test.subs]
[devtools.core :as devtools]))
(devtools/install!) ;; we love https://github.com/binaryage/cljs-devtools
(defn ^:export run [karma]
(karma/run-tests
karma
're-frame.test.middleware
're-frame.test.undo
're-frame.test.subs))

View File

@ -0,0 +1,33 @@
(ns re-frame.test-runner
(:refer-clojure :exclude (set-print-fn!))
(:require
[cljs.test :as cljs-test :include-macros true]
[jx.reporter.karma :as karma :include-macros true]
[devtools.core :as devtools]
;; Test Namespaces -------------------------------
[re-frame.middleware-test]
[re-frame.undo-test]
[re-frame.subs-test]))
(enable-console-print!)
(devtools/install! [:custom-formatters :sanity-hints]) ;; we love https://github.com/binaryage/cljs-devtools
;; ---- BROWSER based tests ----------------------------------------------------
(defn ^:export set-print-fn! [f]
(set! cljs.core.*print-fn* f))
(defn ^:export run-html-tests []
(cljs-test/run-tests
're-frame.middleware-test
're-frame.undo-test
're-frame.subs-test))
;; ---- KARMA -----------------------------------------------------------------
(defn ^:export run-karma [karma]
(karma/run-tests
karma
're-frame.middleware-test
're-frame.undo-test
're-frame.subs-test))

View File

@ -1,4 +1,4 @@
(ns re-frame.test.undo
(ns re-frame.undo-test
(:require [cljs.test :refer-macros [is deftest]]
[re-frame.undo :as undo]
[re-frame.db :as db]

129
test/test.html Normal file
View File

@ -0,0 +1,129 @@
<html lang="en">
<head>
<title>re-frame Unit Tests</title>
<meta charset='utf-8'>
<meta name="google" content="notranslate"/>
<!-- Use a monospaced font and a dark theme -->
<!-- some colour from Palette from http://clrs.cc/ -->
<style>
body {
font-family: Courier, "Courier New", monospace;
font-size: 11;
background-color: #111;
color: #AAA;
margin: 0.25in 0.25in 0.25in 0.25in;
}
h2 {
font-size: 24;
}
.red {
color: #FF4136;
}
.green {
color: #2ECC40;
}
.orange {
color: #FF851B;
}
.blue {
color: #0074D9;
}
.test-header {
color: #EEE;
}
</style>
</head>
<body>
<h2>re-frame Unit Tests</h2>
<div id="output-goes-here"></div>
<script src="../run/compiled/browser/test/goog/base.js" type="text/javascript"></script>
<script src="../run/compiled/browser/test.js" type="text/javascript"></script>
<script>
// This loop is where a lot of important work happens
// It will inject both the unit tests and code-to-be-tested into the page
//find out what requires cljs.core
// reverse nameToPath
var pathToName = {};
for (var key in goog.dependencies_.nameToPath) {
var value = goog.dependencies_.nameToPath[key];
pathToName[value] = key;
}
for (var key in goog.dependencies_.requires) {
if (goog.dependencies_.requires.hasOwnProperty(key)) {
if (goog.dependencies_.requires[key]["cljs.core"]) {
//as key is a path find its namespace
goog.require(pathToName[key]); // will trigger CLOSURE_IMPORT_SCRIPT calls which injectJs into page
}
}
}
// --------------------------------------------------------------------
// Output
var outputDiv = document.getElementById("output-goes-here")
function testPrintLn(line) {
line = line.replace(/\n/g, "");
if (line == "")
return;
line = line.replace(/</g, "&lt;");
line = line.replace(/>/g, "&gt;");
// First, to the console
console.log(line);
// Second, into the HTML
var span = document.createElement("pre");
outputDiv.appendChild(span);
// look for colour markers
if (-1 != line.indexOf('ERRORS:')) {
span.className = "blue"
}
if (-1 != line.indexOf('WARNINGS:')) {
span.className = "blue"
}
if (-1 != line.indexOf('ERROR ')) {
span.className = "orange"
}
if (-1 != line.indexOf('FAIL')) {
span.className = "red"
}
if (-1 != line.indexOf('Testing test.')) {
span.className = "test-header"
}
if (-1 != line.indexOf('failures,')) {
if (-1 != line.indexOf('0 failures, 0 errors')) {
document.body.style.backgroundColor = "#00430D";
span.className = "green";
}
else {
document.body.style.backgroundColor = "771419";
span.className = "red";
}
}
// replace leading blanks with &nbsp; so text lines up
var numLeadingBlanks = line.match(/^\s*/)[0].length;
var leadingNBSP = Array(numLeadingBlanks).join("&nbsp;")
span.innerHTML = leadingNBSP + line + "<br>";
}
// --------------------------------------------------------------------
// Run Tests
//
function run_tests() {
re_frame.test_runner.set_print_fn_BANG_(testPrintLn);
re_frame.test_runner.run_html_tests();
}
// Don't run any tests till this page is fully loaded.
// Remember there'll be lots of async <script> added by the loop above.
window.addEventListener('load', run_tests);
</script>
</body>
</html>