Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is there are plugin structure planned? #12

Closed
pscheit opened this issue Mar 18, 2014 · 18 comments
Closed

Is there are plugin structure planned? #12

pscheit opened this issue Mar 18, 2014 · 18 comments

Comments

@pscheit
Copy link

pscheit commented Mar 18, 2014

Hey there, your attempt to write another assertion library sounds compromising.
Are you planning to write a plugin structure like in chai? I have a lot of complex tests and would love to have something "easier" than the chaijs plugin structure. Maybe something more intuitive ;)

best regards and thank you
philipp

@Nicolab
Copy link

Nicolab commented Mar 18, 2014

Hi,

the easiest and quickest way is to create a (or several) standard module and use it in your tests.

If you want a multi API styles as Chai with Must.js assertions, you can look Unit.js (most assertions are made on top of Must.js, it also embeds other libraries of assertions for more specific things such as HTTP request testing, mock, ...).

Then you might consider creating your plugins in a simple object :

test.isUsername = function(){

  test.must(test.actual).between(2, 10);
  test.must(test.actual).match(/[a-zA-Z0-9]/);

  return test;
};

In your tests suite :

// pass
test.string('foo').isUsername();

// fail because not match with the regex pattern [a-zA-Z0-9]
test.string('foo@bar').isUsername();

// fail, because is not between 2, 10
test.string('f').isUsername();

// fail, because is not between 2, 10
test.string('foooooooooooooooooooo').isUsername();

@moll
Copy link
Owner

moll commented Mar 20, 2014

Hey, @pscheit!

I do have a plan to expose an internal function that Must itself uses for asserting and creating assertion errors — that would help writing custom assertions/plugins on the Must.prototype namespace that will then be thrown with proper error messages.

Were you mostly interested in adding your own assertions to Must's namespace that you could then call in the form of obj.must.awesome()?

You should, however, be able to try something out right away by using the existing assertions. The stack trace your test runner will show (e.g. Mocha) will be a little misleading, though, as it will show that assertion function as the source of failure.

Must.prototype.awesome = function() { this.actual.must.equal("awesome") }
"Something".must.be.awesome()

Thanks, @Nicolab, for pitching in, too! :)

@Nicolab
Copy link

Nicolab commented Mar 21, 2014

Hello,

a suggestion :

Must.register('awesome', assertion, 'error message', diff);

Parameters :

'awesome' : assertion identification that produce must.awesome()

assertion : callback for asserting

'error message : (optional) a custom message if the assertion fails (or optionally accept a callback ?)

diff : (optional) a custom callback for the diff between actual / expected (if the assertion fails)

Something in the style :)

@moll
Copy link
Owner

moll commented Jun 14, 2015

Good news, everyone! Made some progress:

I pondered over the insist function a little and ended up with the idea to export it as Must.prototype.assert (

js-must/must.js

Line 1028 in 77616e8

Must.prototype.assert = function assert(ok, message, opts) {
).

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.

Given the above, to add matchers, one could just assign them to Must.prototype, call Must.prototype.assert within it and call it a day. Would something like this handle most cases?

Thanks in advance!

This was referenced Jun 14, 2015
@estilles
Copy link

Let us know when you publish these so we can start working on our plugins.

@moll
Copy link
Owner

moll commented Jun 14, 2015

Will do. I'm kind of waiting for your feedback first actually to know if it does the trick or needs something further. :-)
You can work off of master by installing it with NPM: npm i git+https://github.com/moll/js-must.git.

@estilles
Copy link

I'll start working on another plugin tomorrow morning.

@estilles
Copy link

@moll, check out must-sinon. I still have a few matchers to add, but the basic plugin functionality is in place and working. So, AFAICT ... Must.js is plugin ready. :-)

@moll
Copy link
Owner

moll commented Jun 15, 2015

Checking it out now. You gave me an idea with those placeholder vars — perhaps rather than always concatenating opts.expected to the assertion failure message, do so only if the message has a placeholder %s. Any pros and cons you see?

@estilles
Copy link

Using placeholders seems like a good idea to me. :-)

@moll
Copy link
Owner

moll commented Jun 16, 2015

They might indeed, but I've got a sneaky feeling we should start with no interpolation nor concatenating initially. The risk with more features off the bat is that it might prevent something better designed later.

@estilles
Copy link

I understand your concern. The upside is that interpolation would allow you to construct a more readable message, since you can interpolate the expected value where it would grammatically fit best, instead of a fixed, concatenated place within the message. The flexibility offered by interpolation is worth considering.

That said, you're in a much better position to gauge whether a feature like this may or may not hinder future features/design.

@moll
Copy link
Owner

moll commented Jun 16, 2015

The stringifying function Must uses for concatenation is currently exported as Must.stringify, so after removing both the concatenation (and not yet adding interpolation), one can still prepare a message with it before calling Must.prototype.assert.

@estilles
Copy link

Yeah ... didn't realize until now that you've exported Must.stringify. Going to use it in must-sinon.

@moll
Copy link
Owner

moll commented Jun 16, 2015

My bad. Haven't documented the developer facing API.
I remembered why I added concatenation to Must.protoytype.assert in the first place — it was to get lazy stringifying — to not do the work of serialization until the assertion actually failed. You might want to pass a function as a message to Must.prototype.assert to get the same behavior now.

@jtwebman
Copy link

jtwebman commented Nov 3, 2015

@moll I went ahead and gave it a shoot with Targaryen plugin called must-targaryen. Could you take a look and give any suggestions if something looks wrong?

@nwinch
Copy link

nwinch commented Feb 5, 2016

I've added another to the mix for JSX comparison - must-jsx.

@moll
Copy link
Owner

moll commented May 22, 2016

Thanks @JohnnyEstilles, @jtwebman and @nwinch for pitching in. I linked to the three modules above in the README: https://github.com/moll/js-must#plugins.

👍 everyone for exporting a function to be called with Must. That's future proof.

I'll close this issue as tweaking Must for extensibility is an ongoing task. So far this.assert seems to cover most cases, apart from one suggestion @nwinch made in #44.

@moll moll closed this as completed May 22, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants