npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

semtest

v3.0.2

Published

NodeJs Unit test framework combining Tape, Proxyquire and Sinon

Downloads

7

Readme

npm version Build Status Coverage Status Code Climate Dependency Status devDependency Status

Semtest

A(nother ?) light unit test framework for nodejs

semtest: (javascript) => TAP

So what is this about ?

Concieved during the time I was writing Semverse, Semtest is a simple yet efficient unit test framework for nodejs apps. Its main goal (besides honing my skills on developing and maintaining an npm module) is to alleviate all the boilerplate around:

  • testing code with Tape (in its Blue-Tape version), which outputs a nice TAP output
  • enforcing unit test best practices, such as no state sharing between tests, function focused tests, and self-documenting code

I also decided that I would apply the same standards I apply on all my current projects:

  • 100 percent unit test coverage
  • JSLint compliance
  • Functional programming all the way !
  • Semantic versioning
  • ES2015 javascript

Installation

Installation is pretty straightforward :

$ npm install --save-dev semtest

Usage

$ node your_spec_file.js

or, since tape allows for globbing, and is a direct dependency of this package anyway:

$ tape '**/*.spec.js'

or, since a lot of us uses build pipelines, you can pipe the sources with your favorite build tool. These specs files are autonomous javascript files so you can run them anyway you want. Hurray, separation of concerns !

Documentation

You execute your unit tests with a clean, predefined structure that will help you both ensure your module works as expected regardless of its dependencies, and document your code behaviour way better than any comment could ever do: executeTests: (moduleDescription, functionAssertions) => TAP output

executeTests is a function that takes as input the module description (for documentation) and an array of function assertions blocks (more on that later) and output unit tests results in TAP format on stdout: executeTests: (moduleDescription, functionAssertionsBlocks) => TAP (on stdout)

// Let's consider a "myModule" method that uses "dependencyC":
myModule.myFunction = (a) => dependencyC(a);

// We can test it like this:
semtest.executeTests("My powerful module", [{
    name: "myFunction()",
    assertions: [{
        when: "it's called with a truthy value",
        should: "return 'qux'",
        test: function (t) {
            t.equal(
                myStubbedModule.myFunction(true),
                "qux"
            );
            t.end();
        }
    }]
}]);

// This will output a TAP stream that you can pipe into TAP readers like faucet or tap-spec, or even Jenkins TAP Plugin

Assertions structure

Assertions are maps that should have these keys:

  • "when" and "should" are properties that will document your unit test. "when" is optional because sometimes you want to test assertions that are always true, thus making "when" akward to define. "Should", on the other hand, is mandatory, of course, because every assertion exist to test a specific result, behaviour, or effect.
  • "test" is the actual unit test, written like a Blue-Tape function, which is a function that take the Blue-Tape assert object as parameter (commonly known as "t") and should either output a promise (whose resolved/rejected status will pass or fail the test) or call the "plan"/"end" Tape methods.
  • You can also use the boolean keys "only" and "skip". The former will allow you to indicate to semtest that you only want a specific assertion to run for its suite, the latter will indiciate that you want to skip this test: it will not be executed and will not appear in the results.

Assertions for a function are bundled in a function assertion block, which is an object with two keys:

  • "name" is the function name
  • "assertions" is an array of assertions, defined above.

executeTests will then, take an array of function assertion blocks as its second input to, as you can expect it, run every unit test, of every function.

Every assertions will then be output on stdout as TAP with a description built like this:

"module" - "function": when "assertion.when", it should "assertion.should"

If we reuse our myModule example and pipe the result in faucet, we'll get:

$ node myModule.spec.js | faucet
myModule - myFunction: when it's called with a truthy value, it should return 'qux'
# tests 1
# pass 1
ok

The additional bonus of such structure is that you can fold your code in spec files to only show the documentation part, enabling your to truly document your code with specs, which they are for in the first place :

executeTests("Test helpers library", [{
    name: "rejectFnHO()",
    assertions: [{
        when: "its returned function is not given a rejection reason",
        should: "return a function that returns the base reason",
        test: (test) => test((t) =>
                [..............................................]
        )
    }, {
        when: "its returned function is given a rejection reason",
        should: "return a function that returns the given reason",
        test: (test) => test((t) =>
                [..............................................]
        )
    }]
}

Here, whatever the [.....] cover, we can focus on the litteral description of our code instead.

Since the spec files aren't meant to be delivered in production, we can make them as bloated as we want, for the sake of code literacy instead of performance.

Coverage

This module is fully compatible with any coverage tool as far as I know. I recommend nyc but you're free to use your favorite, of course !

Utility functions

utilityFunctions is a collection of one-liners that are very useful to stub you dependencies with:

// Instead of defining the same stubs over and over again :
const myModule = myModuleWrapper(
    '~/projects/myProject/myModule.js',
    {
        foo: () => Promise.resolve(true),
        bar: () => Promise.reject(new Error("Oups")),
        baz: () => () => Promise.reject(new Error("Oups")),
        qux: () => () => null,
        derp: (a) => a
    }
);

// We can use utilityFunctions as quicker and more consistent way :
const u = require("semtest").utilityFunctions;

const myModuleMock = {
        foo: u.resolveFn(true),
        bar: u.rejectFn("Oups"),
        baz: u.rejectFnHO("Oups"),
        qux: u.nullFn,
        derp: u.idFn
    }
);

Licence

Do whatever you want with the code, just tell me about it so that I can know at least one person read it xD

Contributing

Open issues and send me PRs like there's no tomorrow, be my guest !