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

migrate Mocha's tests to Unexpected assertion library #3343

Merged
merged 4 commits into from
May 8, 2018

Conversation

boneskull
Copy link
Contributor

@boneskull boneskull commented Apr 21, 2018

These changes convert (nearly) all usages of expect.js and assert to unexpected.

Motivation:

  1. Consistency
  2. Better diffs
  3. Custom assertions (see the new test/assertions.js) are easy to implement
  4. Easier to avoid potentially throwing multiple errors in a single test w/ multiple assertions (see to satisfy)
  5. Out-of-the-box support for Promise
  6. Active development
  • I removed the userland assert b/c as I understand the Node.js team is no longer discouraging the use of the built-in module.
  • chai is added because we have a test that asserts compatibility, which was previously not-so-valuable, because we weren't actually testing against Chai itself. Whether or not we should remove this particular test is debatable.
  • We now have custom assertions for handling the result of runMochaJSON in the integration tests
  • test/unit/runnable.spec.js uses no assertion library. See my comments there and in the Runnable test is bonkers #3342.
  • There's now a test/README.md that explains some things.

@boneskull
Copy link
Contributor Author

should probably fix those windows-only tests.

@coveralls
Copy link

coveralls commented Apr 21, 2018

Coverage Status

Coverage increased (+0.009%) to 90.018% when pulling 85c8f0d on experimental/unexpected into 1606f35 on master.

Copy link
Contributor

@Bamieh Bamieh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK chai/expect are the most familiar stack among developers, maybe this will raise the barrier of contributions?

This is the first time I see unexpected, but it seems interesting.

@boneskull
Copy link
Contributor Author

I’m not too concerned about it creating friction. Even if it did, I feel the benefits of using it outweigh any negatives about the general unfamiliarity with it.

What we should do, however, is document the custom assertions and make it clear where the documentation for the base assertions live. If a contributor is familiar with Chai, it shouldn’t be too jarring, anyway.

That said, to someone unfamiliar with either, I’d argue Unexpected is fundamentally easier to understand than Chai, since it doesn’t do strange things with object properties:

// chai
// this is really weird if you’ve never seen it before
expect(foo).to.be.ok; 

// unexpected
expect(foo, ‘to be ok’);

@Munter
Copy link
Contributor

Munter commented Apr 22, 2018

I'm obviously all for this change. But I'm completely biased, having contributed to the unexpected ecosystem myself.

Copy link
Contributor

@outsideris outsideris left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the first time for 'unexpected' like @Bamieh.
I'm not sure that this is too abstraction or not, but unexpected is interesting.


assert.equal(res.failures[0].title, 'should only display this error');
assert.equal(res.code, 1);
expect(res, 'to have failed')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only one test failed is the matter here not 2.
So, it should be expect(res, 'to have failed test count', 1).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch. note that this implies “to have failed” but to have passed test count does not

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(imply to have passed). sorry on phone

.addAssertion(
'<JSONResult> [not] to have failed [test] count <number>',
function (expect, result, count) {
expect(result.stats.failures, '[not] to be', count);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about expect(result, '[not] to satisfy', {stats: {failures: count}});?

the result of previous is:

expected
{
  stats: {
    suites: 1, tests: 1, passes: 0, pending: 0, failures: 2, start: '2018-04-22T17:06:46.509Z', end: '2018-04-22T17:06:46.513Z',
    duration: 4
  },
  tests: [
    {
      title: 'should only display this error', fullTitle: 'suite1 should only display this error', duration: 1, currentRetry: 0,
      err: ...
    }
  ],
  pending: [],
  failures: [
    {
      title: 'should only display this error', fullTitle: 'suite1 should only display this error', duration: 1, currentRetry: 0,
      err: ...
    },
    { title: '"after all" hook', fullTitle: 'suite1 "after all" hook', duration: 0, currentRetry: 0, err: ... }
  ],
  passes: [], code: 2
}
to have failed test count 1

And the result of satisfy is:

expected
{
  stats: {
    suites: 1, tests: 1, passes: 0, pending: 0, failures: 2, start: '2018-04-22T17:07:42.938Z', end: '2018-04-22T17:07:42.941Z',
    duration: 3
  },
  tests: [
    {
      title: 'should only display this error', fullTitle: 'suite1 should only display this error', duration: 0, currentRetry: 0,
      err: ...
    }
  ],
  pending: [],
  failures: [
    {
      title: 'should only display this error', fullTitle: 'suite1 should only display this error', duration: 0, currentRetry: 0,
      err: ...
    },
    { title: '"after all" hook', fullTitle: 'suite1 "after all" hook', duration: 0, currentRetry: 0, err: ... }
  ],
  passes: [], code: 2
}
to have failed test count 1

{
  stats: {
    suites: 1,
    tests: 1,
    passes: 0,
    pending: 0,
    failures: 2, // should equal 1
    start: '2018-04-22T17:07:42.938Z',
    end: '2018-04-22T17:07:42.941Z',
    duration: 3
  },
  tests: [
    {
      title: 'should only display this error', fullTitle: 'suite1 should only display this error', duration: 0, currentRetry: 0,
      err: ...
    }
  ],
  pending: [],
  failures: [
    {
      title: 'should only display this error', fullTitle: 'suite1 should only display this error', duration: 0, currentRetry: 0,
      err: ...
    },
    { title: '"after all" hook', fullTitle: 'suite1 "after all" hook', duration: 0, currentRetry: 0, err: ... }
  ],
  passes: [],
  code: 2
}

I feel that the result is pretty verbose, but it is straightforward.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, hmmm... so what I didn’t do was create customized diffs for each assertion. you can do this. but didn’t see it as necessary for a first pass.

what you’re saying comes in to play when working with the diffs—I’m not sure which of the two forms will more easily provide a better diff once it’s customized.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. I'm interested in the diff, but I'm also not sure which is better.

@plroebuck
Copy link
Contributor

Had never heard or even seen this of this library; Google searches for expect all reference "chai".
Really dislike the use of 'to be' comparing two different variables; I immediately think of comparing their addresses, not values. That said, glancing the code changes, I notice several places where the new assertion should probably be different.

For example, TAP reporter spec had this:
expect(stdout[0], 'to equal', expectedMessage);
should probably be:
expect(stdout[0], 'to be', expectedMessage);

Similar elsewhere. Sorry, but couldn't comment inline.

@boneskull
Copy link
Contributor Author

to be is a strict equality which is going to be akin to a reference.

@boneskull
Copy link
Contributor Author

and yes, we should probably audit those assertions as this was mostly a search/replace job.

@boneskull
Copy link
Contributor Author

but if it ended up being to equal it was originally .to.eql. in this case it was already incorrect

@boneskull
Copy link
Contributor Author

@plroebuck curious what the value of the Google search is? expect is a variable. I could call it fireball instead.

@plroebuck
Copy link
Contributor

to be is a strict equality which is going to be akin to a reference.

Unexpected's documentation says to be uses SameValue equality, which is different from ===.

@boneskull
Copy link
Contributor Author

@plroebuck you're right. though the documentation page @ ECMA is suspended, apparently?

Either way, their implementation makes more sense, since things like NaN === NaN evaluate to false. thanks javascript

@boneskull
Copy link
Contributor Author

squashed and rebased and reformatted; @outsideris' comment addressed in 03b3c4a

@boneskull boneskull added the semver-patch implementation requires increase of "patch" version number; "bug fixes" label Apr 23, 2018
Squashed commits:
[fc418f8] remove extra call to done() in test/unit/runnable.spec.js
[f1bc24f] lint test/browser-specific/setup.js
[48af58c] fix test flake in ESM test
[346ab5c] convert bundle and browser-specific tests to unexpected
[c76b2f4] fix typo in test/README.md [ci skip]
[783f16a] add test/README.md [ci skip]
[a5949bb] convert all "only" tests to unexpected
[15c921e] lint test/integration/diffs.spec.js
[0d7635e] convert all individual reporter tests to unexpectedalso don't eat `STDOUT`--this means the tests have more output--could be
useful for debugging.
[190f5ed] convert compiler tests to unexpected
[822b115] fix test/integration/glob.spec.js
[db4853d] fix jsapi test
[6f9831d] remove debugs from test/integration/diffs.spec.js
[4cfbe4f] remove useless manual browser tests that will never get used properly
[4e1d97b] convert test/reporters/base.spec.js to unexpected- add `chai` as dependency for `chai`-specific test, since the old one
was based on what we thought it should be, not what it actually is.
- improve test output: stop eating `STDOUT` and use color where possible
[a8378f9] convert test/node-unit/color.spec.js to unexpected
[92f50de] convert test/integration/reporters.spec.js to unexpected
[652a331] remove global assert
[ec857ef] convert test/integration/diffs.spec.js to unexpectedthis required a bit of massaging, since I had to change the
fixture to use `assert`, which produces slightly different output.also move `getDiffs()` out of `test/integration/helpers.js`,
since it's only used in `test/integration/diffs.spec.js`.
[436e85d] remove userland assert moduleit's safe to use the built-in assert module.
[dd7aec7] remove expect.js & karma-expect; add karma-unexpected
[01dff70] lint test/setup.js
[77203bf] convert test/integration/regression.spec.js to unexpected
[e9eb05e] add more assertions; fix others
[241159e] convert test/require/require.spec.js to unexpected
[eb6bcff] convert test/integration/options.spec.js to unexpected
[ada86aa] add custom assertions
[5368ebe] convert test/integration/no-diff.spec.js to unexpected
[043cfe3] convert test/integration/glob.spec.js to unexpected
[df748a3] convert test/integration/compiler-globbing.spec.js to unexpected
[5c0a8d0] convert test/interfaces/tdd.spec.js to unexpected
[c6622a6] convert test/interfaces/qunit.spec.js to unexpected
[1ecd62f] convert test/interfaces/exports.spec.js to unexpected
[cabda05] convert test/interfaces/bdd.spec.js to unexpected
[454018b] convert test/node-unit/stack-trace-filter.spec.js to unexpected
[be6c332] fix unhelpful error thrown from lookupFiles; convert test/node-unit/file-utils.spec.js to unexpected
[419d3ed] convert test/unit/grep.spec.js to unexpected
[4837a6a] convert test/unit/hook-sync-nested.spec.js to unexpected
[6d6b632] convert test/unit/hook-async.spec.js to unexpected
[6ec01eb] convert test/unit/hook-sync.spec.js to unexpected
[d4f6515] convert test/unit/ms.spec.js to unexpected
[c43c096] convert test/unit/mocha.spec.js to unexpected
[7aa9b82] convert test/unit/root.spec.js to unexpected
[13a9e24] convert test/unit/runnable.spec.js to unexpected
[cf9b376] convert test/unit/runner.spec.js to unexpected
[efe37f9] simplify exception tests in test/unit/suite.spec.js
[c08ba9e] convert test/unit/suite.spec.js to unexpected
[41a85d9] convert test/unit/test.spec.js to unexpected
[19f2d44] convert test/unit/throw.spec.js to unexpected
[70ec725] convert test/unit/context.spec.js to unexpected
[8c6cefd] convert test/unit/utils.spec.js to unexpected
[a626278] add unexpected

Signed-off-by: Christopher Hiller <boneskull@boneskull.com>
Signed-off-by: Christopher Hiller <boneskull@boneskull.com>
@boneskull
Copy link
Contributor Author

boneskull commented Apr 30, 2018

weird, how did options.spec.js get reverted...uarggghh

UPDATE: this was actually a new test which was added that I hadn't yet converted

Signed-off-by: Christopher Hiller <boneskull@boneskull.com>
…ter tests

Signed-off-by: Christopher Hiller <boneskull@boneskull.com>
Copy link
Contributor

@Bamieh Bamieh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've just had a full thorough look at the PR. This is awesome work. My only concern was about the community's familiarity with unexpected. But like you mentioned, the syntax is almost identical and easy to comprehend.

@boneskull boneskull force-pushed the master branch 2 times, most recently from 4547268 to 7613521 Compare May 4, 2018 16:47
@boneskull boneskull merged commit 668b541 into master May 8, 2018
@boneskull boneskull deleted the experimental/unexpected branch May 8, 2018 17:49
@boneskull boneskull added this to the next milestone May 8, 2018
@plroebuck
Copy link
Contributor

I know this is already merged, but...

it('should accept a glob "path" value', function() {
var res = utils
.lookupFiles(tmpFile('mocha-utils*'), ['js'], false)
.map(path.normalize.bind(path));
var expectedLength = 0;
var ex = expect(res, 'to contain', tmpFile('mocha-utils.js'));
expectedLength++;
if (symlinkSupported) {
ex = ex.and('to contain', tmpFile('mocha-utils-link.js'));
expectedLength++;
}
ex.and('to have length', expectedLength);
});

I fail to see any value to using expectedLength here, since it's really being used to calculate the actual length. #L58 will always be correct if the other two tests pass.

Should remove all lines containing expectedLength. As a better fix, collect the expected files in an array and spread them in single call to expect(). Something like:

    it('should accept a glob "path" value', function() {
      var res = utils
        .lookupFiles(tmpFile('mocha-utils*'), ['js'], false)
        .map(path.normalize.bind(path));

      var expectedFiles = [
        tmpFile('mocha-utils.js')
      ];
      if (symlinkSupported) {
        expectedFiles.push(tmpFile('mocha-utils-link.js'));
      }
      expect(res, 'to contain', ...expectedFiles);
    });

boneskull added a commit that referenced this pull request May 18, 2018
* convert tests to use Unexpected as assertion library

Squashed commits:
[fc418f8] remove extra call to done() in test/unit/runnable.spec.js
[f1bc24f] lint test/browser-specific/setup.js
[48af58c] fix test flake in ESM test
[346ab5c] convert bundle and browser-specific tests to unexpected
[c76b2f4] fix typo in test/README.md [ci skip]
[783f16a] add test/README.md [ci skip]
[a5949bb] convert all "only" tests to unexpected
[15c921e] lint test/integration/diffs.spec.js
[0d7635e] convert all individual reporter tests to unexpectedalso don't eat `STDOUT`--this means the tests have more output--could be
useful for debugging.
[190f5ed] convert compiler tests to unexpected
[822b115] fix test/integration/glob.spec.js
[db4853d] fix jsapi test
[6f9831d] remove debugs from test/integration/diffs.spec.js
[4cfbe4f] remove useless manual browser tests that will never get used properly
[4e1d97b] convert test/reporters/base.spec.js to unexpected- add `chai` as dependency for `chai`-specific test, since the old one
was based on what we thought it should be, not what it actually is.
- improve test output: stop eating `STDOUT` and use color where possible
[a8378f9] convert test/node-unit/color.spec.js to unexpected
[92f50de] convert test/integration/reporters.spec.js to unexpected
[652a331] remove global assert
[ec857ef] convert test/integration/diffs.spec.js to unexpectedthis required a bit of massaging, since I had to change the
fixture to use `assert`, which produces slightly different output.also move `getDiffs()` out of `test/integration/helpers.js`,
since it's only used in `test/integration/diffs.spec.js`.
[436e85d] remove userland assert moduleit's safe to use the built-in assert module.
[dd7aec7] remove expect.js & karma-expect; add karma-unexpected
[01dff70] lint test/setup.js
[77203bf] convert test/integration/regression.spec.js to unexpected
[e9eb05e] add more assertions; fix others
[241159e] convert test/require/require.spec.js to unexpected
[eb6bcff] convert test/integration/options.spec.js to unexpected
[ada86aa] add custom assertions
[5368ebe] convert test/integration/no-diff.spec.js to unexpected
[043cfe3] convert test/integration/glob.spec.js to unexpected
[df748a3] convert test/integration/compiler-globbing.spec.js to unexpected
[5c0a8d0] convert test/interfaces/tdd.spec.js to unexpected
[c6622a6] convert test/interfaces/qunit.spec.js to unexpected
[1ecd62f] convert test/interfaces/exports.spec.js to unexpected
[cabda05] convert test/interfaces/bdd.spec.js to unexpected
[454018b] convert test/node-unit/stack-trace-filter.spec.js to unexpected
[be6c332] fix unhelpful error thrown from lookupFiles; convert test/node-unit/file-utils.spec.js to unexpected
[419d3ed] convert test/unit/grep.spec.js to unexpected
[4837a6a] convert test/unit/hook-sync-nested.spec.js to unexpected
[6d6b632] convert test/unit/hook-async.spec.js to unexpected
[6ec01eb] convert test/unit/hook-sync.spec.js to unexpected
[d4f6515] convert test/unit/ms.spec.js to unexpected
[c43c096] convert test/unit/mocha.spec.js to unexpected
[7aa9b82] convert test/unit/root.spec.js to unexpected
[13a9e24] convert test/unit/runnable.spec.js to unexpected
[cf9b376] convert test/unit/runner.spec.js to unexpected
[efe37f9] simplify exception tests in test/unit/suite.spec.js
[c08ba9e] convert test/unit/suite.spec.js to unexpected
[41a85d9] convert test/unit/test.spec.js to unexpected
[19f2d44] convert test/unit/throw.spec.js to unexpected
[70ec725] convert test/unit/context.spec.js to unexpected
[8c6cefd] convert test/unit/utils.spec.js to unexpected
[a626278] add unexpected
* fix missing assertion in an "options" integration test
* convert new test in options.spec.js to unexpected
* combine Chai test into a single assertion; increase timeout for reporter tests

Signed-off-by: Christopher Hiller <boneskull@boneskull.com>
sgilroy pushed a commit to TwineHealth/mocha that referenced this pull request Feb 27, 2019
* convert tests to use Unexpected as assertion library

Squashed commits:
[fc418f8] remove extra call to done() in test/unit/runnable.spec.js
[f1bc24f] lint test/browser-specific/setup.js
[48af58c] fix test flake in ESM test
[346ab5c] convert bundle and browser-specific tests to unexpected
[c76b2f4] fix typo in test/README.md [ci skip]
[783f16a] add test/README.md [ci skip]
[a5949bb] convert all "only" tests to unexpected
[15c921e] lint test/integration/diffs.spec.js
[0d7635e] convert all individual reporter tests to unexpectedalso don't eat `STDOUT`--this means the tests have more output--could be
useful for debugging.
[190f5ed] convert compiler tests to unexpected
[822b115] fix test/integration/glob.spec.js
[db4853d] fix jsapi test
[6f9831d] remove debugs from test/integration/diffs.spec.js
[4cfbe4f] remove useless manual browser tests that will never get used properly
[4e1d97b] convert test/reporters/base.spec.js to unexpected- add `chai` as dependency for `chai`-specific test, since the old one
was based on what we thought it should be, not what it actually is.
- improve test output: stop eating `STDOUT` and use color where possible
[a8378f9] convert test/node-unit/color.spec.js to unexpected
[92f50de] convert test/integration/reporters.spec.js to unexpected
[652a331] remove global assert
[ec857ef] convert test/integration/diffs.spec.js to unexpectedthis required a bit of massaging, since I had to change the
fixture to use `assert`, which produces slightly different output.also move `getDiffs()` out of `test/integration/helpers.js`,
since it's only used in `test/integration/diffs.spec.js`.
[436e85d] remove userland assert moduleit's safe to use the built-in assert module.
[dd7aec7] remove expect.js & karma-expect; add karma-unexpected
[01dff70] lint test/setup.js
[77203bf] convert test/integration/regression.spec.js to unexpected
[e9eb05e] add more assertions; fix others
[241159e] convert test/require/require.spec.js to unexpected
[eb6bcff] convert test/integration/options.spec.js to unexpected
[ada86aa] add custom assertions
[5368ebe] convert test/integration/no-diff.spec.js to unexpected
[043cfe3] convert test/integration/glob.spec.js to unexpected
[df748a3] convert test/integration/compiler-globbing.spec.js to unexpected
[5c0a8d0] convert test/interfaces/tdd.spec.js to unexpected
[c6622a6] convert test/interfaces/qunit.spec.js to unexpected
[1ecd62f] convert test/interfaces/exports.spec.js to unexpected
[cabda05] convert test/interfaces/bdd.spec.js to unexpected
[454018b] convert test/node-unit/stack-trace-filter.spec.js to unexpected
[be6c332] fix unhelpful error thrown from lookupFiles; convert test/node-unit/file-utils.spec.js to unexpected
[419d3ed] convert test/unit/grep.spec.js to unexpected
[4837a6a] convert test/unit/hook-sync-nested.spec.js to unexpected
[6d6b632] convert test/unit/hook-async.spec.js to unexpected
[6ec01eb] convert test/unit/hook-sync.spec.js to unexpected
[d4f6515] convert test/unit/ms.spec.js to unexpected
[c43c096] convert test/unit/mocha.spec.js to unexpected
[7aa9b82] convert test/unit/root.spec.js to unexpected
[13a9e24] convert test/unit/runnable.spec.js to unexpected
[cf9b376] convert test/unit/runner.spec.js to unexpected
[efe37f9] simplify exception tests in test/unit/suite.spec.js
[c08ba9e] convert test/unit/suite.spec.js to unexpected
[41a85d9] convert test/unit/test.spec.js to unexpected
[19f2d44] convert test/unit/throw.spec.js to unexpected
[70ec725] convert test/unit/context.spec.js to unexpected
[8c6cefd] convert test/unit/utils.spec.js to unexpected
[a626278] add unexpected
* fix missing assertion in an "options" integration test
* convert new test in options.spec.js to unexpected
* combine Chai test into a single assertion; increase timeout for reporter tests

Signed-off-by: Christopher Hiller <boneskull@boneskull.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
semver-patch implementation requires increase of "patch" version number; "bug fixes" type: cleanup a refactor
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants