";
79 | (node.onclick = showTheProblem).call(node);
80 | }
81 |
82 | function Dary() {
83 | clearDaryTimeou();
84 | overallPass += pass[LENGTH];
85 | overallFail += fail[LENGTH];
86 | overallFatal += fatal[LENGTH];
87 | passTheInfo("(" + join.call([
88 | pass[LENGTH],
89 | ci = fail[LENGTH],
90 | fatal[LENGTH]
91 | ], ", ") + ")");
92 | node = node.parentNode;
93 | fatal[LENGTH] ?
94 | writeItOrdered(fatal, prefix = "error")
95 | : (
96 | ci ?
97 | writeItOrdered(fail, prefix = "fail")
98 | :
99 | prefix = "pass"
100 | )
101 | ;
102 | node.className = prefix;
103 | ci = 0;
104 | prefix = EMPTY;
105 | isGonnaBeLegen();
106 | }
107 |
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 |
2 | var
3 | setup, teardown, jsc
4 | ;
5 |
6 | // node, rhino, and web
7 | try {
8 | // node and phantom js
9 | var wru = this.wru.assert ?
10 | this.wru :
11 | require("./../build/wru.console")
12 | ;
13 | go(wru);
14 | } catch(wru) {
15 | // rhino
16 | try {
17 | load(
18 | new java.io.File(".").getCanonicalPath() +
19 | "/build/wru.console.js"
20 | );
21 | go(wru);
22 | } catch(wru) {
23 | try {
24 | // jsc test/test.js
25 | load(
26 | "build/wru.console.js"
27 | );
28 | jsc = true;
29 | go(wru);
30 | } catch(wru) {
31 | // html (assuming test.html is used in same folders structure)
32 | (function(xhr){
33 | try {
34 | xhr.open("get", "./../build/wru.min.js", true);
35 | xhr.onreadystatechange = function () {
36 | if (xhr.readyState == 4) {
37 | try {
38 | Function(xhr.responseText.replace(/var wru=/,"this.wru=")).call(window);
39 | } catch(e) {
40 | alert(e);
41 | }
42 | go(window.wru);
43 | }
44 | };
45 | xhr.send(null);
46 | } catch(e) {
47 | alert(e.message || e);
48 | }
49 | }(new XMLHttpRequest));
50 | }
51 | }
52 | }
53 |
54 | function go(wru) {
55 |
56 | wru.test([{
57 | name: "test that should pass",
58 | test: function () {
59 | wru.assert("it passes", 1);
60 | }
61 | },{
62 | name: "async test",
63 | test: function () {
64 | if (jsc) {
65 | wru.log("JavaScriptCore does not support timers (yet)");
66 | wru.assert("OK");
67 | } else {
68 | setTimeout(wru.async(function (arg) {
69 | wru.assert("OK", "OK" === arg);
70 | wru.assert(setup === 1);
71 | wru.assert(teardown == null);
72 | }), 2000, "OK");
73 | }
74 | },
75 | setup: function () {
76 | setup = 1;
77 | },
78 | teardown: function () {
79 | teardown = 1;
80 | }
81 | },{
82 | name: "test that should fail",
83 | test: function () {
84 | wru.assert("this passes", true);
85 | wru.assert("this fails", 0);
86 | }
87 | },{
88 | name: "test that should throw an error",
89 | test: function () {
90 | wru.assert("it's an error", 1);
91 | WTF++;
92 | }
93 | },{
94 | name: "test that should be pass synchronously even if the callback was created via async",
95 | test: function () {
96 | function sync() {wru.assert(++executed)}
97 | var executed = 0;
98 | jsc ? sync() : wru.async(sync)();
99 | wru.assert(executed);
100 | }
101 | }]);
102 | }
103 |
--------------------------------------------------------------------------------
/src/wru.console.functions.js:
--------------------------------------------------------------------------------
1 | // console specific version
2 | function isGonnaBeLegen() {
3 | current = shift.call(queue);
4 | if (current) {
5 | if (typeof current == "function") {
6 | current = {name: current[NAME] || "anonymous", test: current};
7 | }
8 | log(OUTPUT_SEPARATOR);
9 | log(
10 | (iHasIt(current, NAME) && current[NAME])
11 | ||
12 | (iHasIt(current, DESCRIPTION) && current[DESCRIPTION])
13 | ||
14 | UNKNOWN
15 | );
16 | pass = [];
17 | fail = [];
18 | fatal = [];
19 | tmp = {};
20 | giveItATry("setup");
21 | fatal[LENGTH] || giveItATry("test");
22 | waitForIt || Dary();
23 | } else {
24 | showSummary();
25 | }
26 | }
27 |
28 | function log(info, avoidNewLine) {
29 | info = info + (avoidNewLine ? "" : "\n");
30 | try {
31 | // node 0.11+ alternative ...
32 | process.stdout.write(info);
33 | } catch(up) {
34 | try {
35 | // node 0.6
36 | require("util").print(info);
37 | } catch(up) {
38 | try {
39 | // node 0.4
40 | require("sys").print(info);
41 | } catch(up) {
42 | try {
43 | // hello Rhino
44 | // print uses println ... while we need print without \n
45 | java.lang.System.out.print(info);
46 | } catch(up) {
47 | try {
48 | // phantomjs or default fallback
49 | console.log(info);
50 | } catch(up) {
51 | // jsc and others
52 | print(info);
53 | }
54 | }
55 | }
56 | }
57 | }
58 | }
59 |
60 | function showSummary() {
61 | var code = 0, status;
62 | log(EMPTY);
63 | log(OUTPUT_SEPARATOR);
64 | switch (true) {
65 | case !!overallFatal:
66 | code++;
67 | status = "error";
68 | log(ERROR + " " + overallFatal + " Errors");
69 | break;
70 | case !!overallFail:
71 | code++;
72 | status = "fail";
73 | log(FAILURE + EMPTY + overallFail + " Failures");
74 | break;
75 | default:
76 | status = "pass";
77 | log(OK + " " + overallPass + " Passes");
78 | }
79 | wru.status = status;
80 | log(OUTPUT_SEPARATOR);
81 | log(EMPTY);
82 | wru.after();
83 | try {
84 | // node.js
85 | process.exit(code);
86 | } catch(up) {
87 | // rhino
88 | quit();
89 | }
90 | }
91 |
92 | function writeItOrdered(fail) {
93 | for (var
94 | i = 0, length = fail[LENGTH];
95 | i < length;
96 | log(" " + (++i) + ". " + fail[i - 1])
97 | );
98 | }
99 |
100 | function Dary() {
101 | clearDaryTimeou();
102 | overallPass += pass[LENGTH];
103 | overallFail += fail[LENGTH];
104 | overallFatal += fatal[LENGTH];
105 | if (fatal[LENGTH]) {
106 | prefix = ERROR;
107 | writeItOrdered(fatal);
108 | } else if(fail[LENGTH]) {
109 | prefix = FAILURE;
110 | writeItOrdered(fail);
111 | } else {
112 | prefix = OK;
113 | }
114 | log(prefix + " passes: " + pass[LENGTH] + ", fails: " + fail[LENGTH] + ", errors: " + fatal[LENGTH]);
115 | ci = 0;
116 | prefix = EMPTY;
117 | isGonnaBeLegen();
118 | }
119 |
--------------------------------------------------------------------------------
/src/wru.js:
--------------------------------------------------------------------------------
1 |
2 | var // wru library core
3 | wru = {
4 | timeout: TIMEOUT,
5 | assert: function assert(description, result) {
6 |
7 | // if no description provided, variables are shifted
8 | // these are both valid wru.assert calls indeed
9 | // wru.assert(truishValue);
10 | // wru.assert("test description", truishValue);
11 | if (arguments[LENGTH] == 1) {
12 | result = description;
13 | description = UNKNOWN;
14 | }
15 |
16 | // flag used in wru.async to verify at least
17 | // one assertion was performed
18 | called = TRUE;
19 |
20 | // store the result in the right collection
21 | push.call(result ? pass : fail, prefix + description);
22 |
23 | // just to add a bit of sugar
24 | return result;
25 | },
26 | async: function async(description, callback, timeout, p) {
27 | var r, delay = timeout || wru.timeout || (wru.timeout = TIMEOUT);
28 | // p is used as sentinel
29 | // it defines the anonymous name
30 | // if necessary and it's used to flag the timeout
31 | p = ++waitForIt;
32 |
33 | // if no description provided, variables are shifted
34 | // these are all valid wru.async calls indeed, timeout is optional
35 | // wru.async(function () { ... })
36 | // wru.async("test description", function () { ... })
37 | // wru.async(function () { ... }, timeout)
38 | // wru.async("test description", function () { ... }, timeout)
39 | if (typeof description == "function") {
40 | delay = callback || wru.timeout;
41 | callback = description;
42 | description = "asynchronous test #" + p;
43 | }
44 |
45 | // if in *TIMEOUT* time nothing happens ...
46 | timeout = setTimeout(function () {
47 |
48 | // p is flagged as 0
49 | p = 0;
50 |
51 | // timeout is handled as failure, not error (could be the server)
52 | push.call(fail, description);
53 |
54 | // if there is no reason to waitForIt then is time to call Dary()
55 | --waitForIt || (daryTimeout = setTimeout(Dary, 0));
56 | },
57 | // timeout can be specified
58 | // this procedure ensure that it's
59 | // a number and it's greater than 0
60 | abs(delay) || wru.timeout
61 | );
62 |
63 | // the async function is a wrap of the passed callback
64 | return function async() {
65 |
66 | // if it's executed after the timeout nothing happens
67 | // since the failure has been already notified
68 | if (!p) return;
69 |
70 | // called is always set as *TRUE* during any assertion
71 | // this indicates if the callback made at least one assertion
72 | // as example, in this case the callback could be called many time
73 | // with different readyState ... however, only on readyState 4
74 | // there is the assertion we are interested about, e.g.
75 | //
76 | // xhr.onreadystatechange = wru.async(function (){
77 | // if (this.readyState == 4)
78 | // wru.assert("content", this.responseText.length)
79 | // ;
80 | // });
81 | //
82 | // in above example called will be flagged as true
83 | // only during last readyState call
84 | called = FALSE;
85 |
86 | // simply recycled "string" variable
87 | // prefix will be internally used by assert during function execution
88 | prefix = description + ": ";
89 |
90 | // the original callback is called with proper *this* if specified
91 | try {
92 | r = callback.apply(this, arguments);
93 | } catch(doooodeThisIsBAD) {
94 | // if there is an Error
95 | // the test is screwed up
96 | // called has to be set as *TRUE* to invalidate the test
97 | called = TRUE;
98 | // message is "casted" to avoid IE host objects errors problem
99 | // (or any other possible edge case)
100 | push.call(fatal, prefix + doooodeThisIsBAD);
101 | }
102 |
103 | // prefix can be *EMPTY* string again now
104 | prefix = EMPTY;
105 |
106 | // a failure or at least an assertion
107 | if (called) {
108 |
109 | // timeout not necessary anymore
110 | clearTimeout(timeout);
111 |
112 | // if there is no reason to waitForIt then is time to call Dary()
113 | --waitForIt || (daryTimeout = setTimeout(Dary, 0));
114 | }
115 |
116 | // return the eventual callback value
117 | return r;
118 | };
119 | },
120 |
121 | // wru.test({...test...})
122 | // wru.test([{...test...}, {...test...}, ...])
123 | // the {...test...} object should have a string name and a function test property
124 | // optionally a function setup and a function teardown too
125 | test: function test(list, after) {
126 |
127 | // in case you need to do something after
128 | wru.after = after || function () {};
129 |
130 | // test may be called multiple times
131 | // queue should simply concatenate other calls
132 | queue = concat.apply(queue, [list]);
133 |
134 | // if wru.random is true, the queue is ranodomized
135 | // this is to make tests indipendent from each others
136 | wru.random && sort.call(queue, messItUp);
137 |
138 | // if there is no test to waitForIt
139 | // Dary() has been called already
140 | // we can procede with next test
141 | // invoking isGonnaBeLegen()
142 | waitForIt || isGonnaBeLegen();
143 | }
144 | },
145 |
--------------------------------------------------------------------------------
/test/solutions.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | wru
5 |
118 |
119 |
120 |
121 |
122 |
123 |
155 |
156 |
157 |
158 |
164 |
165 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | wru :: JavaScript tests have never been that easy
2 | =================================================
3 |
4 | *wru* is an **essential general purpose test framework** compatible with **web** environment, [node.js](http://nodejs.org/), [Rhino](http://www.mozilla.org/rhino/), and now [PhantomJS](http://www.phantomjs.org/) too.
5 |
6 |
7 | features
8 | --------
9 |
10 | * **runs in both client and server environments**, compatible with html files, node.js, Rhino, PhantomJS, and JavaScriptCore.
11 | * **both synchronous and asynchronous tests** in an absolutely intuitive way
12 | * **ES5 and JS.next ready**, compatible with `"use strict"` directive which means no `with` statements, `eval`, or misused `this` references
13 | * **easy**, probably the easiest way to test JS code out there thanks to its simplified API: `test`, `assert`, `async`, and `log` ... you already remember "*all of them*", isn't it?
14 | * **unobtrusive** and **self defensive**, since everything that could possibly change in such dynamic environment as JS is, is "*sandboxed*" inside the *wru closure*. This means no matter how "*nasty*" your code is, *wru* won't pollute or change the global environment, neither it will rely in native *constructor.prototypes* changes (`Array.prototype.push = ...` or `Object.prototype.hasOwnProperty = ...`? not a problem!)
15 | * **cursor included in both web and console** ... you gonna realize how much "[THE CURSOR](http://www.3site.eu/cursor/)" is important, specially to understand if your test is **stuck** or simply "*waiting for*" ... cursor is working in both Unix and OSX consoles (unfortunately PhantomJS does not support the cursor while jsc does not support timers at all)
16 | * **tiny**, even if it's not important in tests world, *wru* fits into about 2Kb (1.2Kb *minzpped*) which means not much to fix or change here, just a simple, reliable, and essential framework for your tests
17 | * **under your control**, since there is absolutely **no magic behind the *wru* scene**. You assert what you want, you async what you need, you describe what's needed, and you are *ready to go* in less than 5 minutes
18 |
19 | If you can't believe it check [html](https://github.com/WebReflection/wru/blob/master/test/test.html), [node.js](https://github.com/WebReflection/wru/blob/master/test/testnode.js), [Rhino](https://github.com/WebReflection/wru/blob/master/test/testrhino.js), or [PhantomJS](https://github.com/WebReflection/wru/blob/master/test/phantom.js) test and see how *wru* does work ;-)
20 |
21 |
22 | compatibility
23 | -------------
24 |
25 | *wru* is compatible with basically all possible browsers out there included **IE5.5**, **IE6**, **IE7**, **IE8**, **IE9**, **IE10**, **Chrome**, **Firefox**, **Safari**, **Webkit** based, **Mobile Browsers**, and **Opera**.
26 |
27 | On server side *wru* is compatible with latest **node.js**, **Rhino**, **PhantomJS**, and **JavaScriptCore** versions. I swear if *I find an easy way to* easily *test Spider/Iron/JagerMonkey I will support them* too.
28 |
29 |
30 | how to test wru
31 | ---------------
32 |
33 | The simplest way to test wru is to use [template.html](https://raw.github.com/WebReflection/wru/master/build/template.html) for **web** tests or [template.js](https://raw.github.com/WebReflection/wru/master/build/template.js) for **node**, **rhino**, and **jsc** tests or [template.phantom.js](https://github.com/WebReflection/wru/blob/master/build/template.phantom.js) for **PhantomJS** tests.
34 |
35 | With these 3 options you don't even need to fork or download the entire repository ... but if you do that ...
36 |
37 | From *wru* root directory, simply run these commands accordingly with what you want to test:
38 |
39 | // node.js test
40 | node test/test.js
41 |
42 | // Rhino
43 | java -jar builder/jar/js.jar test/test.js
44 |
45 | // PhantomJS test
46 | phantomjs test/phantom.js
47 |
48 | // JavaScriptCore test
49 | jsc test/test.js
50 |
51 | // web (through Mac OSX but you can open test.html with any browser)
52 | open test/test.html
53 |
54 | **PhantomJS** supports tests for both plain JavaScript in a blank page, or any url adding it as argument.
55 |
56 | // PhantomJS test on about:blank
57 | phantomjs build/template.phantom.js
58 |
59 | // PhantomJS test on any url
60 | phantomjs build/template.phantom.js "http://yourwebsite.com"
61 |
62 | **PhantomJS** tests should always starts when the DOM has been already parsed.
63 |
64 | **JavaScriptCore** does not implement (yet) setTimeout and setInterval so it's not possible to test via `async()` calls.
65 |
66 | If you forked the project, you made some change, and you want to **rebuild wru**, this is all you have to do:
67 |
68 | // still inside wru folder
69 | python builder/build.py
70 |
71 | // or now with node
72 | node builder/build.js
73 |
74 | After the build process is finished, no more than 3 seconds with forced waiting time included to read stats if build has been *double-clicked*, you should be able to run again the test for your own environment.
75 |
76 | Please bear in mind **JSbuilder.(js|py)** works with **node-js 0.4+** or **Python < 3** (2.6 or 2.7 are fine) so be sure you have it (you should by default on Mac or Linux).
77 |
78 |
79 | wru basics
80 | ----------
81 |
82 | // probably all you need as "one shot" test
83 | wru.test({
84 | name: "Hello wru!",
85 | test: function () {
86 | wru.assert("it works!", 1);
87 | }
88 | });
89 |
90 | // for multiple tests ... pass an Array
91 | wru.test([{
92 | name: "test #1",
93 | setup: function () {
94 | // setup before the test
95 | },
96 | test: function () {
97 | // async test example
98 | setTimeout(wru.async(function () {
99 | wru.assert("executed", true);
100 | }), 1000);
101 | },
102 | teardown: function () {
103 | // clean up after the test
104 | }
105 | },{
106 | name: "test #2",
107 | test: function () {
108 | // do other stuf here
109 | }
110 | }]);
111 |
112 | To know more about *wru* possibilities ... please keep reading ;-)
113 |
114 |
115 | wru API
116 | =======
117 |
118 | There are truly few things you need to know, and even less properties you need to configure!
119 |
120 |
121 | methods
122 | -------
123 |
124 | * `test(object)` or `test([object, ..., object])` to execute one or more tests. A generic test object may have one or more properties:
125 | * `test` property, as **function**, to execute the test with one or more `wru.assert()` or `wru.async()` calls. **optional** but recommended
126 | * `name` or `description` property, as **string**, to have visual knowledge of the current test **optional**
127 | * `setup` property, as **function**, that will be executed right before the test: **optional**
128 | * `teardown` property, as **function**, that will be executed right after the test: **optopnal**
129 | * `assert("description", truishOrFalsyValue)` to manually assert whatever you want where **description is optional** (but suggested) and the assertion is compatible with *truish* or *falsy* values. You are in charge of strictly compared results if necessary by *===* operator, nothing new to learn here
130 | * `async("description", callback, timeout)` to tell *wru* that a test will be executed at some point later and where **both description and timeout are optionals**
131 | * `log(anything, forceFallback)` the equivalent of *console.log(obj)* where supported, the equivalent of *alert()* or *print()* if the *forceFallback* flag is set to true (or better, *truish*)
132 |
133 |
134 | properties
135 | ----------
136 |
137 | * `random`, as `true` or `false`, to make tests order execution random (by default `false`)
138 | * `node` on **web version only** to set a different node from the default one (which is an element with `id == "wru"`or the `document.body` or the `document.documentElement` if `body` is not present yet)
139 |
140 |
141 | test properties
142 | ---------------
143 | Each test can be either an object or, if you are that lazy typer, a function.
144 |
145 | * `name` as test *title* or *test name*, if the test is a function the function name (expression or declared) will be used where available, anonymous otherwise.
146 | * `setup` as function to do something before the test is executed. Bear in mind every test will receive a freshly baked object as argument, from setup, to test, and teardown, the same object. Use it if you need.
147 | * `test` as function to execute if the test is not a function itself. Receives the shared object per test as first argument.
148 | * `teardown` as function to do something after the test is executed. Receives the same shared object setup and test receive as argument.
149 |
150 |
151 | how does wru work
152 | =================
153 |
154 | following a list of explained tasks that are possible with *wru*
155 |
156 |
157 | synchronous tests and wru.assert()
158 | ----------------------------------
159 | Every test **may** have one or more `wru.assert()` calls inside. The method itself accepts one or two arguments. Following a sequence of valid operations.
160 |
161 | // the test object ...
162 | {
163 | name: "existance test",
164 | test: function () {
165 |
166 | // example only: if next property is not
167 | // null, undefined, 0, false, "", or NaN
168 | // the assertion will pass the test
169 | wru.assert("callback exists", window.onload);
170 |
171 | // if necessary, assertion can be strict without problems
172 | wru.assert(
173 | "it is a callback",
174 | typeof window.onload === "function"
175 | );
176 |
177 | // the description is visually useful
178 | // if the test fails but it's not mandatory
179 | // next example is still valid, no description
180 | wru.assert("isArray" in Array);
181 |
182 | // if a condition supposes to be truish
183 | // wru.assert can make test life easier
184 | // returning the asserted value
185 | if (wru.assert("defineProperty" in Object)) {
186 | wru.assert(
187 | Object.defineProperty({}, "_", {value: true})._
188 | );
189 | }
190 |
191 | }
192 | }
193 |
194 |
195 | asynchronous tests and wru.async()
196 | ----------------------------------
197 | Every test is performed synchronously unless there is one or more `wru.async()` calls. In latter case all tests after the current one will be waiting for the asynchronous call to be executed.
198 | When it happens, if the asynchronous call performed one or more assertions, the framework keep going without requiring any extra step: **is that easy!**
199 |
200 | // the test object ...
201 | {
202 | name: "load content",
203 | test: function () {
204 | // asynchronous test example
205 |
206 | // this will be synchronous
207 | wru.assert("condition accepted", true);
208 |
209 | // this will be asynchronous
210 | var xhr = new XMLHttpRequest;
211 | xhr.open("get", "file.txt", true);
212 | xhr.onreadystatechange = wru.async(function () {
213 | if (this.readyState === 4) {
214 |
215 | // only on readyState 4 there is an assertion
216 | wru.assert("text is not empty", this.responseText.length);
217 |
218 | // if necessary, async call can be nested
219 | setTimeout(wru.async(function () {
220 | wru.assert(
221 | "DOM changed in the meanwhile",
222 | docment.body.innerHTML != storedLayout
223 | );
224 | }, 500));
225 | }
226 | });
227 | xhr.send(null);
228 |
229 | // this will be performed regardless
230 | wru.assert("something else to check", 1);
231 | }
232 | }
233 |
234 | In above example, the `onreadystatechange` function may be executed many times on different `readyState`. The *wru* logic cannot care less about it since an asynchronous callback is considered *done* when **at least one assertion has been performed**.
235 | If this does not happen the internal `TIMEOUT` constant, by default 10 seconds, will kill the procedure.
236 | You have to admit there is no reason to create an asynchronous test without performing some assertion inside the callback ... and this is where *wru* is smart.
237 | If many assertions have been defined and one of them is not reached is most likely because there was an error or a failure in the test.
238 | *wru* tracks all tests without problems so forget things such `lib.expectedAssertions(3)` and "*friends*" ... you really may not need that!
239 |
240 |
241 | the temporary object
242 | --------------------
243 |
244 | If needed, every `setup`, `test`, or `teardown` function will receive a "*freshly new backed*" object for the current test.
245 | This can be handy to store some reference or value on `setup`, use them during the `test`, and drop them during the `teardown` if necessary.
246 |
247 | // the test object ...
248 | {
249 | name: "tmp object all over",
250 | setup: function (tmp) {
251 | tmp.global = window;
252 | tmp.global.random = Math.random();
253 | },
254 | test: function (tmp) {
255 | wru.assert(
256 | tmp.global === window // true
257 | );
258 | wru.assert(
259 | typeof tmp.global.random == "number" // true again
260 | );
261 | },
262 | teardown: function (tmp) {
263 | delete tmp.global.random;
264 | delete tmp.global;
265 | }
266 | }
267 |
268 |
269 | the build process
270 | =================
271 |
272 | *wru* is based on [javascript-builder](http://code.google.com/p/javascript-builder/) which is able to aggregate distributed files in order to produce the final library/framework even if the source/JS logic is split in more files.
273 |
274 | This is the *wru* case, where some file is dedicated for web environment rather than console/shell one.
275 | If you fork the project and you make some change/improvement, first of all let me know :-), secondly remember to re-build the script.
276 | This is the list of files actually created by *wru build process* inside the *build* folder:
277 |
278 | * **wru.console.max.js** is the full script console/shell related, suitable for *node.js* or *rhino* tests
279 | * **wru.console.js** is the minified version of the precedent one with `wru.debug()` stripped out
280 | * **wru.dom.js** is the full script DOM related, suitable for *web* and *browsers*
281 | * **wru.min.js** is the minified version of the precedent one with `wru.debug()` stripped out
282 |
283 | `wru.debug()` is a method used to export, track, test, or change internals. You should never use this method unless strictly necessary but it's there for debugging purpose.
284 | `wru.debug()` is automatically removed from built versions so that no evaluation of internals can be possible.
285 |
286 | If you want to have an overall view of the framework check already built output since if not familiar with this build process it may be hard at the beginning.
287 |
288 | This is the [HTML version](https://github.com/WebReflection/wru/blob/master/build/wru.dom.js), and this is the [console one](https://github.com/WebReflection/wru/blob/master/build/wru.console.max.js), you will notice things make sense there since the order is specified in the [build.py](https://github.com/WebReflection/wru/blob/master/builder/build.py) file.
289 |
290 | Please remember all you have to do to build *wru* is this call in the *wru* project root
291 |
292 | python builder/build.py
293 |
294 |
295 | wru against others
296 | ==================
297 |
298 | Other tests frameworks may offer more than what *wru* does but this rarely comes for free.
299 | Some of them may have such complicated/articulated logic that it may happens is the test framework itself that's failing rather than your code.
300 | Also you need to read a lot of documentation and most likely to obtain something already possible with *wru*.
301 | I am not saying *wru* is the best test framework out there, I am just saying you should consider your requirements before you chose a test framework ;-)
302 | In any case, *wru* aim is to make any sort of test simplified and under control.
303 |
304 | As example: "*do you really need so much 'magic' to perform these tasks?*"
305 |
306 | // rather than specify expected arguments
307 | // via magic/complicated operations
308 | function (a, b, c) {
309 | wru.assert("received numbers",
310 | typeof a == "number"
311 | &&
312 | typeof b == "number"
313 | &&
314 | typeof c == "number"
315 | );
316 | }
317 |
318 | // rather than specify returned values
319 | // via magic/complicated operations
320 | wru.assert(typeof callbac() != "undefined");
321 |
322 | // did you know the console object
323 | // may have already an assert() method
324 | // since that's basically all you need?
325 | wru.assert(
326 | "if true, I can get rid of wru since all I need is 'assert'",
327 | "assert" in console
328 | );
329 |
330 | // the only reason wru may be handy is the
331 | // cross platform/environment compatibility
332 | // and its async method interlaced with
333 | // current environment layout (HTML or shell/console/bash)
334 | wru.assert("oh come on but this is so easy!", 1);
335 |
336 | Just give it a try ;-)
337 |
338 |
339 | HTML VS console
340 | ===============
341 |
342 | *wru* core functionality is exactly the same in both environments ... it cannot be easier to maintain, imo.
343 | However, there are few substantial differences between HTML results and those shown in the console
344 |
345 |
346 | HTML tests
347 | ----------
348 |
349 | * based on classes, easily to customize via [CSS](https://github.com/WebReflection/wru/blob/master/test/wru.css)
350 | * differential colors accordingly with test results: green if successful, red if failed, black if cryptical (e.g. unmanaged exceptions)
351 | * failures or errors are not shown by default, **one click** to see the list of problems in any of those non green tests
352 | * summary on top, no need to scroll 'till the end of the document to understand how it was. A nice summary with all passed, failed, or unmanaged errors test is shown on top
353 |
354 |
355 | console tests
356 | -------------
357 |
358 | * based on `stdout`
359 | * differential prefixes accordingly with test results: `[OK]` if successful, `[FAILURE]` if failed, `[ERROR]` if cryptical (e.g. unmanaged exceptions)
360 | * failures and errors are always listed in the output
361 | * summary always at the end of the test
362 |
363 |
364 | I need a setup per each test!
365 | =============================
366 |
367 | Sure you do :-)
368 |
369 | // just create a simple wrapper before your tests
370 | // to fully automate the procedure
371 | wru.test = (function (test) {
372 |
373 | // we got a closure here, do whaveter you want!
374 | function whateverSetupIsNeeded(tmp) {
375 | // do setup stuff
376 | }
377 |
378 | return function (testObjects) {
379 | // be sure it's an array, convert otherwise
380 | testObjects = [].conca(testObjects);
381 |
382 | // per each object
383 | for (var
384 | // reassign the setup if present
385 | reassign = function (setup) {
386 | testObjects[i].setup = function (tmp) {
387 | whateverSetupIsNeeded(tmp);
388 | setup && setup(tmp);
389 | };
390 | },
391 | i = testObjects.length; i--;
392 | reassign(testObjects[i].setup)
393 | );
394 |
395 | // invoke wru.test() which is self bound
396 | test(list);
397 |
398 | // that's pretty much it
399 | };
400 |
401 | }(wru.test));
402 |
403 | Similar technique if you need same teardown call per each test.
404 |
405 |
406 | I need other edge cases too !
407 | =============================
408 |
409 | The cool part is that being simple, *wru* is also highly customizable.
410 | Please keep an eye in the [solutions.html](https://github.com/WebReflection/wru/blob/master/test/solutions.html) file.
411 | I will try to update it as soon as some *request or edge case* comes up.
412 |
413 |
414 | wrap it if you want
415 | ===================
416 |
417 | If you think *wru* is too simple, you still have a chance to improve it wrapping its basic methods and create something wonderful out of it.
418 | Arguments automations? Returned values? Expected number of calls per callback?
419 |
420 | The *wru* cross environment core is easy to hack for anybody, check [wru.js](https://github.com/WebReflection/wru/blob/master/src/wru.js) and your are already half way through ;-)
421 |
422 |
423 | license
424 | =======
425 |
426 | *wru* general purpose test framework and the rest of the project is under Mit Style License
427 |
428 | Copyright (C) 2011 by Andrea Giammarchi, @WebReflection
429 |
430 | Permission is hereby granted, free of charge, to any person obtaining a copy
431 | of this software and associated documentation files (the "Software"), to deal
432 | in the Software without restriction, including without limitation the rights
433 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
434 | copies of the Software, and to permit persons to whom the Software is
435 | furnished to do so, subject to the following conditions:
436 |
437 | The above copyright notice and this permission notice shall be included in
438 | all copies or substantial portions of the Software.
439 |
440 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
441 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
442 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
443 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
444 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
445 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
446 | THE SOFTWARE.
447 |
448 |
449 | OT: some fun during wru development
450 | -----------------------------------
451 |
452 | If you check the built source you will realize that a `wru.test()` lifecycle is between a call to internal `isGonnaBeLegen()` function, passing through the `waitForIt` variable if some asynchronous call has been required, and ending up into the `Dary()` callback.
453 |
454 | I know you don't care but at least now you know how is the `wru.test()` lifecycle :{D
--------------------------------------------------------------------------------