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

@pmoo/testy

v7.0.2

Published

A minimal testing framework, for educational purposes.

Downloads

59

Readme

Testy

ci
maintainability tech-debt coverage Mutation testing badge
Maintainability Rating Technical Debt Reliability Rating Security Rating
GitHub Repo stars open-issues closed-issues open-prs
downloads dependencies
package-size activity release-date
all-contributors

A very simple JS testing framework, for educational purposes. Live at npm at @pmoo/testy.

:arrow_right: Documentación en español aquí :construction_worker: Contributing guidelines

Sponsors

Getting started

npm install --save-dev @pmoo/testy (if you use npm)
yarn add --dev @pmoo/testy (if you use yarn)

Supported Node versions: 18.x or higher (versions with active and security support listed here)

Usage

Writing test suites

A test suite is a file ending _test.js that looks like this:

// my_test.js
import { suite, test, assert } from '@pmoo/testy';

suite('a boring test suite', () => {
  test('42 is 42, not surprising', () => {
    assert.that(42).isEqualTo(42);
  });
});

A test suite represents a grouping of tests, and it is implemented as a function call to suite passing a name and a zero-argument function, which is the suite body.

A test is implemented as a function call to test(), passing a name and the test body as a zero-argument function.

Inside the test you can call different assertions that are documented in detail later on.

Running Testy

You can run an individual test file using:

$ npx testy my_test.js 

Or, you can run it without arguments to run all the tests (by default it looks on a tests folder located in the project root):

$ npx testy 

You can also add it as the test script for npm/yarn in your package.json:

{
  ...
  "scripts": {
    "test": "npx testy"
  },
  ...
}

And then run the tests using npm test or yarn test.

Configuring Testy

Testy will look for a .testyrc.json configuration file in the project root directory. You can use this configuration as a template (values here are the defaults):

{
  "directory": "./tests",   // directory including your test files
  "filter": ".*_test.js$",  // which convention to use to recognize test files
  "language": "en",         // language of the output messages. "es" and "en" supported for now
  "failFast": false,        // enable/disable fail fast mode (stop as soon as a failed test appears)
  "randomOrder": false      // enable/disable execution of tests in random order
  "timeoutMs": 1000         // sets the per-test timeout in milliseconds
}

These are all the configuration parameters you can set. Feel free to change it according to your needs. When declaring this configuration, every test suite under the tests directory (matching files ending with *test.js) will be executed.

Examples and available assertions

There must be at least one assertion on the test to be valid. These are all the supported assertion types:

  • Boolean assertions:
    • assert.that(boolean).isTrue() or assert.isTrue(boolean). It does a strict comparison against true (object === true)
    • assert.that(boolean).isFalse() or assert.isFalse(boolean). It does a strict comparison against false (object === false)
  • Equality assertions:
    • assert.that(actual).isEqualTo(expected) or assert.areEqual(actual, expected).
    • assert.that(actual).isNotEqualTo(expected) or assert.areNotEqual(actual, expected)
    • Equality assertions use a deep object comparison (based on Node's assert module) and fail if objects under comparison have circular references.
    • Equality criteria on non-primitive objects can be specified:
      • Passing an extra two-arg comparator function to isEqualTo(expected, criteria) or areEqual(actual, expected, criteria)
      • Passing a method name that actual object understands: isEqualTo(expected, 'myEqMessage') or areEqual(actual, expected, 'myEqMessage')
      • By default, if actual has an equals method it will be used.
      • If we compare undefined with undefined using isEqualTo(), it will make the test fail. For explicit check for undefined, use the isUndefined()/isNotUndefined() assertions documented above.
  • Identity assertions:
    • assert.that(actual).isIdenticalTo(expected) or assert.areIdentical(actual, expected)
    • assert.that(actual).isNotIdenticalTo(expected) or assert.areNotIdentical(actual, expected)
    • Identity assertions check if two references point to the same object using the === operator.
  • Check for undefined presence/absence:
    • assert.that(aValue).isUndefined() or assert.isUndefined(aValue)
    • assert.that(aValue).isNotUndefined() or assert.isNotUndefined(aValue)
  • Check for null presence/absence:
    • assert.that(aValue).isNull() or assert.isNull(aValue)
    • assert.that(aValue).isNotNull() or assert.isNotNull(aValue)
  • Exception testing:
    • assert.that(() => { ... }).raises(error) or with regex .raises(/part of message/)
    • assert.that(() => { ... }).doesNotRaise(error)
    • assert.that(() => { ... }).doesNotRaiseAnyErrors()
  • Numeric assertions:
    • assert.that(aNumber).isNearTo(anotherNumber). There's a second optional argument that indicates the number of digits to be used for precision. Default is 4.
  • String assertions:
    • assert.that(string).matches(regexOrString) or assert.isMatching(string, regexOrString)
  • Array inclusion:
    • assert.that(collection).includes(object)
    • assert.that(collection).doesNotInclude(object)
    • assert.that(collection).includesExactly(...objects)
  • Emptiness
    • assert.that(collection).isEmpty() or assert.isEmpty(collection)
    • assert.that(collection).isNotEmpty() or assert.isNotEmpty(collection)
    • the collection under test can be an Array, a String or a Set

Please take a look at the tests folder, you'll find examples of each possible test you can write. Testy is self-tested.

Running testy globally

If you don't have a NPM project you can install testy globally using npm install -g testy and then run testy <files>

Other features

  • Running code before/after every test: just like many testing frameworks have, there is a way to execute some code before or after each test in a suite using the before() and after() functions, respectively. You can use only one definition of before() and after() per suite, and they always receive a function as argument. Example:

    import { suite, test, assert, before, after } from '@pmoo/testy';
      
    suite('using the before() and after() helpers', () => {
      let answer;
      
      before(() => {
        answer = 42;
      });
      
      test('checking the answer', () => {
        assert.that(answer).isEqualTo(42);
      });
    
      after(() => {
        answer = undefined;
      });
    });
  • Support for pending tests: if a test has no body, it will be reported as [WIP] and it won't be considered a failure.

  • Support for asynchronous tests: if the code you are testing has async logic, you can await inside the test definition and make assertions later. You can also use it on before() and after() declarations. Example:

    import { suite, test, assert, before } from '@pmoo/testy';
      
    const promiseOne = async () => Promise.resolve(42);
    const promiseTwo = async () => Promise.resolve(21);
    
    suite('using async & await', () => {
      let answerOne;
      
      before(async () => {
        answerOne = await promiseOne();
      });
      
      test('comparing results from promises', async () => {
        const answerTwo = await promiseTwo();
        assert.that(answerOne).isEqualTo(42);
        assert.that(answerTwo).isEqualTo(21);
      });
    });
  • Fail-Fast mode: if enabled, it stops execution in the first test that fails (or has an error). Remaining tests will be marked as skipped.

  • Run tests and suites in random order: a good test suite does not depend on a particular order. Enabling this setting is a good way to ensure that.

  • Strict check for assertions: if a test does not evaluate any assertion while it is executed, the result is considered an error. Basically, a test with no assertion is considered a "bad" test.

  • Explicitly failing or marking a test as pending: there's a possibility of marking a test as failed or pending, for example:

    import { suite, test, fail, pending } from '@pmoo/testy';
      
    suite('marking tests as failed and pending', () => {
      test('marking as failed', () =>
        fail.with('should not be here'));
        
      test('marking as pending', () =>
        pending.dueTo('did not have time to finish'));
    });

    The output includes the messages provided:

    [FAIL] marking as failed
      => should not be here
    [WIP] marking as pending
      => did not have time to finish

Why?

Why another testing tool? The main reason is that we want to keep simplicity, something it's hard to see in the main testing tools out there.

  • Zero dependencies: right now, this project does not depend on any npm package, making the tool easy to install, and fast: essential to have immediate feedback while doing TDD. This is also good for installing on places where the internet connection is not good and we don't want to download hundreds of libraries.
  • Understandable object-oriented code: we want to use this tool for teaching, so eventually we'll look at the code during lessons, and students should be able to see what is going on, and even contributing at it, with no dark magic involved. Also, we try to follow good OO practices.
  • Unique set of features: we are not following any specification nor trying to copy behavior from other approaches (like the "xUnit" or "xSpec" way).

"Design Principles Behind Smalltalk" is a source of inspiration for this work. We try to follow the same principles here.

Contributing

Please take a look at the Contributing section.

Contributors

Thanks goes to these wonderful people (emoji key):

This project follows the all-contributors specification. Contributions of any kind welcome!