DEPRECATED. Use any sane assertion library instead.
Overview
Yet Another Better Assert. assert(expression)
. If truthy–yay! If falsy: Error with the
expression! Cross-browser.
Example:
var assert =
Error: assert(3 < 2)
More examples: (in CoffeeScript)
- Comparison with LearnBoost/expect.js
- yaba uses itself to test itself!
Installation
npm install yaba
or component install lydell/yaba
CommonJS: var assert = require("yaba")
AMD and regular old browser globals: Use ./yaba.js
Tests
Node.js: npm test
Browser: Open ./test/browser/index.html
Usage
yaba(expression)
Pretty much already explained.
yaba.actual && yaba.expected && yaba.message
You can give extra information to yaba by assigning the above properties, which it will use during the next run—and only then. This way, you can let other tools make yaba show details about why an assertion failed. An example:
assert = require "yaba"equals = require "equals" # https://github.com/jkroso/equals = assert.actual = actual assert.expected = expected equalsactualexpected# require compiler, fs/read, etc. assert equal compilercompileread"input.file"read"input.file.expected"
Now, each time you call equal
it will set up .actual
and .expected
for the next yaba call.
yaba then puts those properties on the error it throws. It also sets .showDiff
to true
.
If your testing frameworks supports error.actual
and error.expected
(like mocha) you will now
get nice diffs if the compiler
is buggy, etc.
Just make sure that you always call equal
inside yaba
, so you don't leak the information to the
next yaba call.
yaba.message
will be appended to the message of the thrown error. That is used by the throws
module. An example:
assert = require "yaba"throws = require "throws"throws.messageHolder = assert assert throws TypeError-> throw
Error: Assertion 1 failed. Expected the error to be an instance of `TypeError`.
assert throws TypeError, -> throw new Error
throws sets .message
for the next yaba call. Just like equal
, only call it inside yaba
.
You can of course set it manually, to display a custom message:
assert.message = "My custom extra message"assert false
Error: Assertion 1 failed. My custom extra message
assert false
But it is probably a better idea to use a comment:
assert false # My custom extra message
Error: Assertion 1 failed.
assert false # My custom extra message
That's why yaba only takes one parameter, as opposed to many other assert functions which take two (an expression and an optional message).
error.yaba && yaba.error
Initially I wanted to throw a custom AssertionError
so you could error instanceof AssertionError
check stuff. However, subclassing Error
sucks in JavaScript, so I took a different approach. You
may check if error.yaba
is truthy or not, or, for the paranoid, if error.yaba === yaba.error
.
How it works
Modern browsers put a stack
property on error objects, containing a stack trace. yaba
constructs a new error, and then uses parse-stack to get the file path to the file containing the
yaba()
call, as well as the line number and column number (if available) of the call. It then
reads the source file (note about local testing), and cuts out the assert
expression
at the given position.
Better yet, if you're running CoffeeScript files via the coffee
command, the stack trace will
point to the original CoffeeScript source, giving you the expression in CoffeeScript. (Requires
CoffeeScript 1.7.0 or later). That's currently not possible in any browser.
If the environment does not put a stack
property on error objects, yaba still works. You just
don't get the expression in the error message. You still get something like "Assertion 15 failed",
though. The number of runs is actually stored in assert.runs
. If you plan to use it a lot in some
old browser, you perhaps would like to reset that before each test, like beforeEach -> assert.runs = 0
, to ease the debugging.
Quirks
tl;dr: Format your code sanely and you'll be fine.
The expression will start at the given column number, or if none is available, the beginning of the line. So if you care about for example Firefox and iOS Safari, put all asserts at the beginning of the line (after any indentation). If not, do it anyway. It's readable.
The expression will end at the end of the line. So don't put other stuff on the same line as an assert, if you don't want it to show up in the error messages. It's not worth parsing the JavaScript to find the exact end of the expression. Moreover, compile-to-js languages should be supported too. Last but not least, it could be seen as a feature: Any useful comments after an assert will be included. Even if you don't care: Don't put anything after an assert anyway. Why would you?
I said that the expression ends at the end of the line. That's not really true. Multi-line asserts are supported—as long as you indent each subsequent line more than the first one. Do that anyway. It's readable.
Well, the last thing I said wasn't really true either. The last line of a multi-line expression
can be on the same indentation level if it starts with common "ending" characters, such as ]})"'
.
And if such a line is immediately followed by a more indented line, the process starts over. So the
following should work:
;// The above line should not be mistaken to belong to `assert`.
One caveat, for CoffeeScript users:
assert string is """ The three ending quotes are going to be missing."""assert string is """ You could write it this way instead. """
While talking about indentation. Never mix spaces and tabs. That'll confuse yaba, you and everyone else. Don't.
Why "yaba"? What's the difference compared to other assertion libs?
It's an acronym for "Yet Another Better Assert" since it is inspired by visionmedia/better-assert, this fork of it for CoffeeScript support, rhoot/cassert and component/assert.
The difference is that it works not only in Node.js or V8-powered browsers, but a lot of other
browsers as well. It has the potential to support compile-to-js languages, and currently does so for
CoffeeScript in Node.js. And when it cannot get the expression, it is helpful by giving you the
assertion count. Oh, and don't forget the .actual
, .expected
and .message
.
As a Star Wars fan, I also like that "yaba" sounds a bit like "Jabba" [the Hutt].