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 🙏

© 2026 – Pkg Stats / Ryan Hefner

ecmatest

v0.0.4

Published

A pytest-like testing framework for JavaScript build on top of Jest

Downloads

7

Readme

ECMATest (JSTest)

Embrace the modern test-making vibe. Inspired by amazing pytest and built on top of Jest.

npm install ecmatest

After installation, the jstest command will be available in your environment. This command automatically searches for test files in your current directory and all subdirectories, following these filename patterns:

async function findTestFiles(dir) {
    return await glob([
            `${dir}/**/*.test.{js,mjs}`,
            `${dir}/**/test.*.{js,mjs}`,
            `${dir}/**/test*.{js,mjs}`,
        ], { 
            nocase: true, 
            ignore: [`${dir}/**/node_modules/**`] 
        }
    );
}

API

fixture

Fixture is what one uses to setup a test. Fixtures can be chained by referencing them as formal parameters by other fixtures or tests. But note fixture function has to use object destructuring syntax. The fixture definition order doesn't matter. Fixtures can have scopes function, module, session.

Fixtures are lazily instantiated - they're only evaluated when referenced directly or indirectly by a test. This applies transitively to all fixture dependencies. Broader-scoped fixtures can not reference narrower-scoped ones.

Fixtures can be generators. This is how one can implement tear down. In the example below, the fakeTimers fixture mocks system timers during test execution and restores real timers afterward. Everything above the yield keyword is the setup section, and everything below is the teardown section.

Fixtures are executed according scope as 1. session, 2. module, 3. function. Note that session-scoped fixtures persist even after the current test module completes. This means fixture side effects can spread across modules - for example, if you set the fakeTimers fixture scope to session, timers will remain mocked until the entire test session finishes.

Currently, you can only reference fixtures from the same module. (Future plans include adding conftest.mjs config files to make global fixtures available and improve session scope functionality).

import { fixture, test, createAutospec, jestFakeTimers, jestMocker } from 'ecmatest';


fixture(function theBeginning() {
    return new Date(0);
}, {scope: 'module'});


fixture(function* fakeTimers({theBeginning}) {
    const fakeTimers = jestFakeTimers();
    fakeTimers.useFakeTimers();
    fakeTimers.setSystemTime(theBeginning);
    yield fakeTimers;
    fakeTimers.useRealTimers();
}, {scope: 'module'});


fixture(function networkMock({ mocker }) {
    const mock = createAutospec(Network.prototype);
    mock.recv = mocker.fn(() => 'failure');
    // or
    // mock.recv.mockReturnValue('failure');
    return mock;
});


fixture(function mocker() {
    return jestMocker();
}, {scope: 'session'})


fixture(function sut({ networkMock }) {
    return new Protocol(networkMock);
});

test

Tests are declared via test decorator and refer fixtures in the same way as fixtures. Tests can use expect just as you would use in Jest.

import { expect } from 'expect';


test("Send hello", ({ sut, networkMock }) => {
    sut.sendHello();
    expect(networkMock.send).toBeCalledWith('hello');
});


test("Fake timers test", ({fakeTimers, theBeginning}) => {
    expect(new Date()).toEqual(theBeginning);

    fakeTimers.advanceTimersByTime(60000);
    expect(new Date()).toEqual(new Date(60000));
});

parametrize

Tests can be parametrized.

test(
    "Multiplication with various inputs",
    parameterize(
        [2, 3, 6],
        [4, 4, 16],
        [0, 5, 0]
    )(function testMultiply({ sut }, a, b, expected) {
        expect(sut.multiply(a, b)).toBe(expected);
    })
);

jest wrappers

To mock ECMAScript class or an Object one can use createAutospec. For classes, use createAutospec(SomeClass.prototype); For objects use createAutospec(someObject) directly.

Under the hood, this uses Jest's mocking functionality. The implementation is straightforward, as shown below. The mocks are compatible with expect since they are Jest mocks and provide the API documented in the Jest documentation.

Object returned by jestMocker has the interface described here in the Jest docs. For fakeTimers see this. Note that out of the box the only advanceTimers (provided by jest ModernFakeTimers class) is available. But it's possible to create LegacyFakeTimers in the same way it's done for modern timers, though the config is slighly different.

import jestFT from '@jest/fake-timers';


export function jestMocker() {
    return new jestMock.ModuleMocker(globalThis);
};


export function jestFakeTimers(config={ global, config: {} }) {
    return new jestFT.ModernFakeTimers(config);
}


export function createAutospec(obj) {
    const mocker = jestMocker();
    return mocker.generateFromMetadata(mocker.getMetadata(obj));
}

[!NOTE] The object returned by jestMocker() has these methods: clearAllMocks(), resetAllMocks(), restoreAllMocks(). These methods only affect mocks created by that specific mocker instance. In practice, they're rarely needed in this paradigm since new mocks are created for each test while old ones are destroyed during teardown. They may only be useful for module and session scoped mocks.

What's next...

  1. Implement conftest.mjs feature
  2. Make Jest runner
  3. Add fixture parametrization from within test setup
  4. Add hooks
  5. Add markers feature

See examples in ./examples folder.