Detalhes do pacote

must

moll47k0.13.4

Testing and assertion library with friendly BDD syntax — awesome.must.be.true(). Many expressive matchers and is test runner and framework agnostic. Follows RFC 2119 with its use of MUST. Good and well tested stuff.

assert, assertion, bdd, test

readme (leia-me)

Must.js

NPM version Build status

Must.js is a testing and assertion library for JavaScript and Node.js with a friendly BDD syntax (awesome.must.be.true()). It ships with many expressive matchers and is test runner and framework agnostic. Follows RFC 2119 with its use of MUST. Good and well testsed stuff.

For those new to testing JavaScript on Node.js, you'll also need a test framework (also called a test-runner or a harness) to run your tests. One such tool is Mocha.

Tour

  • Assert with a beautiful and fluent chain that saves you from wrapping objects manually and reads nicely, too:

    require("must/register")
    obj.must.be.true()
    
  • Supports the expect flavor of wrapping as well:

    var demand = require("must")
    demand(obj).be.string()
    
  • Many expressive matchers out of the box, including:

    [].must.be.empty()
    obj.must.have.nonenumerable("foo")
    (42).must.be.above(13)
    
  • Simple, because matchers always behave the same way and don't depend on any "special flags" in the chain. They are also not interdependent the way foo.should.have.property(x).with.lengthOf(5) would be.

  • Reasonable, because it asserts only when you call the matcher [].must.be.empty() and not when you merely get the property empty. See below why asserting on property access is dangerous in other assertion libraries.

  • Has an intelligent and type-safe recursive eql matcher that compares arrays and objects by content and supports value objects. It's fully type-safe, so instances of different classes aren't eql, even if their properties are. It also supports circular and self-referential objects.

    primesBelowTen.must.eql([2, 3, 5, 7])
    model.attributes.must.eql({title: "New", createdAt: new Date(2000, 1, 1)})
    
  • Built-in support for asserting on promises with stack traces leading back to your assertion, not to the library's internals.

    Promise.resolve(42).must.then.equal(42)
    Promise.resolve([1, 2, 3]).must.eventually.not.include(42)
    Promise.reject(new Error("Problemo")).must.reject.with.error(/problem/i)
    
  • Human readable error messages let you know if an object wasn't what you expected. You can also customize or prepend to the autogenerated error message for further clarification.

  • Honors RFC 2119 by using the word MUST because your tests assert things, they don't list wishes or prayers, right? Exactly! Foo.must.equal(42), not foo.pretty.please.equal(42).

  • Works with any test runner and framework.

  • Avoids type coercions and mismatches.
  • Well tested — over 700 cases in over 2500 lines of tests. That makes a test to code ratio of 5:1.

Using Should.js or Chai.js? Switch for safety!

Among other things, one reason why Should.js and Chai.js inspired me to write Must.js is that they have a fundamental design mistake that makes them both surprising in a bad way and dangerous to use. Read more below.

Extensible

Must.js features a very simple implementation and one you can extend yourself. In Must.js, every matcher is a function on Must.prototype that calls Must.prototype.assert. For now, please see the source of Must for examples.

There are plugins for Must.js by others available, too.

Installing

Note: Must.js will follow the semantic versioning starting from v1.0.0.

Installing on Node.js

npm install must

Installing for the browser

Must.js doesn't yet have a build ready for the browser, but you might be able to use Browserify to have it run there till then.

Using

To use the fluent chain, just require Must.js's "register" file and it'll make itself available everywhere:

require("must/register")

Then just access the must property on any object and call matchers on it.

answer.must.equal(42)
new Date().must.be.an.instanceof(Date)

If you wish to use the expect flavor, assign Must to any name of your choice, e.g:

var expect = require("must")
var demand = require("must")

And call it with the object you wish to assert:

expect(answer).to.equal(42)
demand(null).be.null()

For a list of all matchers, please see the Must.js API Documentation.

Negative asserting or matching the opposite

To assert the opposite, just add not between the chain:

true.must.not.be.false()
[].must.not.be.empty()

Use it multiple times to create lots of fun puzzles! :-)

true.must.not.not.be.true()

Asserting on null and undefined values

In almost all cases you can freely call methods on any object in JavaScript. Except for null and undefined.

Most of the time this won't be a problem, because if you're asserting that something.must.be.true() and something ends up null, the test will still fail. If, however, you do need to assert its nullness, aliasing Must to expect or demand and wrapping it manually works well:

var demand = require("must")
demand(something).be.null()
demand(undefined).be.undefined()

If you've got an object on which a null or an undefined property must exist in addition to having a nully value, use the property matcher:

var obj = {id: null, name: undefined}
obj.must.have.property("id", null)
obj.must.have.property("name", undefined)

Autoloading

If your test runner supports an options file, you might want to require Must there so you wouldn't have to remember to require in each test file.

For Mocha, that file is test/mocha.opts:

--require must/register

Full example

Inside a test runner or framework things would look something like this:

require("must/register")
var MySong = require("../my_song")

describe("MySong", function() {
  it("must be creatable", function() {
    new MySong().must.be.an.instanceof(MySong)
  })

  it("must have cowbell", function() {
    new MySong().cowbell.must.be.true()
  })

  it("must not have pop", function() {
    new MySong().must.not.have.property("pop")
  })
})

API

For extended documentation on all functions, please see the Must.js API Documentation.

Must

Migrating to Must.js

You're likely to be already using some testing library and have a set of tests in them. I'm honored you picked Must.js to go forward. Let's get you up to speed on how Must.js differs from others and how to migrate your old tests over.

From Should.js

Must.js and Should.js are fairly similar when it comes to matchers.

  • Just add parentheses after each assertion and you're almost set.
  • Must.js does not have static matchers like should.not.exist(obj.foo).
    Convert to demand(foo).not.to.exist().
  • Must.js lacks with.lengthOf because its matchers are all independent.
    Convert to obj.must.have.length(5)
  • Must.js lacks the ok matcher because unambiguous names are better.
    Convert to truthy.
  • Must.js does not support custom error descriptions.

Here's a quick sed script to convert obj.should.xxx style to obj.must.xxx():

sed -i.should -E -f /dev/stdin test/**/*.js <<-end
  /\.should\.([[:alpha:].]+)([[:space:]}\);]|$)/s/\.should\.([[:alpha:].]+)/.must.\1()/g
  s/\.should\.([[:alpha:].]+)/.must.\1/g
end

From Chai.js

Must.js and Chai.js are fairly similar when it comes to matchers.

  • Just add parentheses after each assertion and you're almost set.
    That goes for both the BDD (obj.should) and expect (expect(obj).to) flavor.
  • Must.js lacks the include flag because its matchers are all independent.
    Convert to Object.keys(obj).must.include("foo").
  • Must.js lacks the deep flag for the equal matcher because eql already compares recursively and in a type-safe way.
    Convert to obj.must.eql({some: {deep: "object"}}).
  • Must.js lacks the deep flag for the property matcher because it prefers regular property access.
    Convert to obj.some.nested.property.must.equal(42).
  • Must.js lacks the ok matcher because unambiguous names are better.
    Convert to truthy.
  • Must.js lacks the respondTo matcher because unambiguous names are better.
    Convert to MyClass.prototype.must.be.a.function().

Here's a quick sed script to convert obj.should.xxx style to obj.must.xxx():

sed -i.should -E -f /dev/stdin test/**/*.js <<-end
  /\.should\.([[:alpha:].]+)([[:space:]}\);]|$)/s/\.should\.([[:alpha:].]+)/.must.\1()/g
  s/\.should\.([[:alpha:].]+)/.must.\1/g
end

Convert test case titles to MUST

If you've used the should style before, you most likely have test cases titled it("should do good").
Migrate those to it("must do good") with this sed script:

sed -i.should -E -e 's/it\("should/it("must/g' test/**/*.js

Beware of libraries that assert on property access

Among other things, one reason why Should.js and Chai.js inspired me to write Must.js is that they have a fundamental design mistake that makes them both surprising in a bad way and dangerous to use.

It has to do with them asserting on property access, like this:

true.should.be.true
[].should.be.empty

What initially may seem familiar to Ruby programmers, first of all, is out of place in JavaScript. Dot-something stands for getting a property's value and getters, regardless of language, should not have side-effects. Especially not control-flow changing exceptions!

Secondly, and this is where it's flat out dangerous asserting on property access, is that accessing a non-existent property does nothing in JavaScript. Recall that JavaScript does not have Ruby's method_missing or other hooks to catch such access. So, guess what happens when someone mistypes or mis-remembers a matcher? Yep, nothin' again. And that's the way it's supposed to be. But what's good in JavaScript, not so good for your now false positive test.

Imagine using a plugin that adds matchers for spies or mocks. Then using it with someFn.should.have.been.calledOnce. Someone accidentally removes the plugin or thinks calledQuadrice sounds good? Well, those assertions will surely continue passing because they'll now just get undefined back.

Must.js solves both problems with the simplest but effective solution — requires you to always call matchers because they're plain-old functions — expect(problem).to.not.exist().

Plugins

If you have a module extending Must.js one not listed above, please let me know or create a pull request.

License

Must.js is released under a Lesser GNU Affero General Public License, which in summary means:

  • You can use this program for no cost.
  • You can use this program for both personal and commercial reasons.
  • You do not have to share your own program's code which uses this program.
  • You have to share modifications (e.g bug-fixes) you've made to this program.

For more convoluted language, see the LICENSE file.

About

Andri Möll typed this and the code.
Monday Calendar supported the engineering work.

If you find Must.js needs improving, please don't hesitate to type to me now at andri@dot.ee or create an issue online.

changelog (log de mudanças)

0.13.4 (Jan 13, 2017)

  • Tweaks Must.prototype.be et al. implementation to prevent source-map-support from throwing an exception during call stack retrieval. This only happened if that module was used with Must.js for source map support.

0.13.3 (Jan 12, 2017)

  • Adds a first draft of TypeScript definitions.
    Thanks, Karl Purkhardt!
  • Serialize NaNs in objects in error messages as "[NaN]".

0.13.2 (Jul 20, 2016)

  • Fixes stringifying Symbols for assertion errors.
  • Stringifies RegExps nested in objects for assertion errors.
  • Adds symbol.
  • Adds properties.
  • Adds ownProperties.
  • Adds preliminary support for running under strict mode ("use strict").
    Assertion error stack traces will contain one Must.js function at the top at the moment. This will be fixed!

0.13.1 (Sep 26, 2015)

  • Adds custom error message to Must.

0.13.0 (Sep 26, 2015)

  • Lucky version. No changes since the previous release candidate.

0.13.0-rc1 (Sep 22, 2015)

  • Refactors eql to internally use Egal.js, which was extracted from Must.js.

    Must.js augments egal to continue to allow you to assert equivalence to NaNs and instances of classes that aren't value objects. Egal.js doesn't compare those out of the box as they're not things you want to do in production code.

    With the transition to Egal.js, eql now also supports value objects that return compound values. See Egal.js's README for details.

0.13.0-beta2 (Jun 15, 2015)

  • Fixes the stack trace when using promises with some particular matchers.

0.13.0-beta1 (Jun 15, 2015)

  • Adds must that returns self for those of us who sometimes write it twice:

    demand(undefined).must.be.undefined()
    
  • Fixes a false positive in eql when an object had some keys set to undefined.

  • Adds the for a fluent chain.
  • Changes boolean to not consider boxed boolean objects as booleans.
  • Changes number to not consider boxed number objects as numbers.
  • Changes string to not consider boxed string objects as strings.
  • Changes true and false to not consider boxed boolean objects as either true or false.

  • Adds resolve and reject for asserting on promises.
    The former is also aliased to then and [eventually] for different language styles.

    With Mocha, using this will look something like:

    it("must pass", function() {
      return Promise.resolve(42).must.resolve.to.equal(42)
    })
    

    Using CoMocha, it'll look like:

    it("must pass", function*() {
      yield Promise.resolve(42).must.resolve.to.equal(42)
      yield Promise.resolve(42).must.then.equal(42)
      yield Promise.reject(42).must.reject.and.equal(42)
    })
    
  • Adds with for a fluent chain.

  • Adds error to assert on errors.
    Similar to throw, but useful for when you already have an error at hand.
  • Adds startWith.
  • Adds endWith.
  • Adds nan to test NaN.

0.12.0 (May 28, 2014)

0.11.0 (Feb 13, 2014)

  • Works on other JavaScript engines besides V8 by not assuming Error.captureStackTrace. Thanks, Dmitry Starostin!

0.10.0 (Oct 31, 2013)

  • Allows asserting NaNs with eqlNaN.must.eql(NaN).

0.9.1 (Oct 31, 2013)

  • Fixes eql to consider two equivalent boxed Boolean, Number or String values eql.
    Previously it only did so if both were primitive (42) or only one was boxed (new Number(42)).

0.9.0 (Oct 28, 2013)

  • Adds between to assert that a value is between a range.

0.8.0 (Oct 27, 2013)

  • Allows asserting and comparing circular and self-referential objects with eql. Objects that are self-referential in the exact same way are considered eql.
  • Displays circular and self-referential objects and arrays in assertion error messages properly.
  • Displays object's inherited properties in assertion error messages.

0.7.0 (Oct 23, 2013)

  • Adds contain as an alias of include.

  • Adds before as an alias of below to make comparing dates read more natural:

    new Date(2000, 5, 18).must.be.before(new Date(2001, 0, 1))
    
  • Adds after as an alias of above to make comparing dates read more natural:

    new Date(2030, 5, 18).must.be.after(new Date(2013, 9, 23))
    

0.6.0 (Oct 15, 2013)

  • Allows asserting both the exception constructor and its message together in the throw matcher:

    someFunction.must.throw(RangeError, /out of bounds/)
    

0.5.0 (Oct 13, 2013)

  • Sets the eql matcher's AssertionError diffable so some test runners would print out a property-by-property diff for mismatches. This helps visual comparison.

0.4.0 (Oct 11, 2013)

  • Changes eql so it also compares instances of the same class recursively like it does with plain objects.
    If the instance has a valueOf function, however, its output is used as before.

0.3.0 (Oct 5, 2013)

  • Allows asserting property and ownProperty on all types (such as functions, booleans etc.), not only objects.
  • Allows asserting keys and ownKeys on all types (such as functions, booleans etc.), not only objects.
  • Allows asserting enumerable and nonenumerable properties on all types (such as functions, booleans etc.), not only objects.

0.2.0 (Sep 26, 2013)

  • Fails gracefully if property matchers (property, enumerable etc.) are used on non-objects.
  • Adds the keys matcher to test if an object has all the expected keys.
    Takes inherited keys into account just like the empty and property matchers.
  • Adds the ownKeys matcher to test if an object has all the expected keys of its own.

0.1.338 (Sep 26, 2013)

0.1.337 (Sep 24, 2013)

  • First release. Must-have!