moll / js-must

An 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 stuff and well tested.
Other
336 stars 35 forks source link

Make `must` extensible #24

Closed estilles closed 9 years ago

estilles commented 9 years ago

Allow must to be extended using community developed assertion/matcher plugins. This would allow for consumers to easily add either their own or community provided matchers, without bloating the must core library. We could easily add assertions for promises (see issue #22), Express request/response objects, etc.

I propose using the typical .use() syntax. For example:

var must = require("must")
var mustPromise = require('must-promise')
must.use(mustPromise);

... or something similar.

moll commented 9 years ago

Hey!

I'm with you. Allowing extensibility is most sensible.

We might need to provide a function or two to ease asserting and throwing an error to simplify creating custom matchers. Internally I added a function for that at https://github.com/moll/js-must/blob/d09d3689a409bae8f1b2e8e5b403da0e83607cf0/lib/assertions.js#L995, but that's not part of the public API right now.

Also, I'm not 100% sure does Must need to know when its being extended[1] vs just allowing extensions to do whatever they please[2]. Something like a promise plugin could just be called last and it would iterate over existing matcher functions to wrap them for promise support.

  1. Must.use
  2. require("must-promise")(require("must"))
estilles commented 9 years ago

@moll ... I'm open to either solution.

I completely agree that must would need to expose the existing private insist() function, but also the chain() function (could be useful in certain use-cases).

Which ever solution you decide, I'll be glad to pitch in. :-)

Already have a few plugins in mind, so I hope this lands soon!

estilles commented 9 years ago

@moll, I create a simple proof of concept at JohnnyEstilles/must-promise. Let me know what you think.

estilles commented 9 years ago

@moll, updated my proof of concept with some additional matchers. Let me know what you think.

moll commented 9 years ago

Hey,

I pondered over the insist function a little and ended up with the idea to export it as Must.prototype.assert (https://github.com/moll/js-must/blob/77616e892cfaed31181d634b544e46bd85d5e421/must.js#L1028). That was the thing I wanted to chat with you about. Would like to hear your thoughts on it.

In short, it works like any assert function ever:

Must.prototype.truthy = function() {
  this.assert(this.actual, "be truthy")
}

Given an object with {expected} as the third argument sets the expected property on the assertion error and concatenates its stringified value to the end of the message string:

Must.prototype.null = function() {
  this.assert(this.actual === null, "be", {expected: null})
}

If you give a function instead of a string, that function will be called for the message should the assertion fail. You can still pass expected in an options object, but instead of concatenating, it'll only be for AssertionError.

So, give me a call and-or reply here when you get around to it. Thanks!

moll commented 9 years ago

Let's continue this conversation over at https://github.com/moll/js-must/issues/12.