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

@mostajs/mjs-unit

v0.3.0

Published

Micro-framework de test pour l'écosystème @mostajs/* : zéro dépendance, API minimale (test/expect/run), runner CLI (preuves HTML/JSON via --report), reporters réutilisables (./report), et un resolver ESM qui exécute sous Node les dist à imports sans exten

Readme

@mostajs/mjs-unit

Auteur : Dr Hamid MADANI [email protected] · Licence : AGPL-3.0-or-later

Micro-framework de test zéro dépendance pour l'écosystème @mostajs/*. Trois apports :

  1. API minimale : test(), describe(), expect() + assertions (ok, equal, deepEqual, throwsAsync, doesNotThrowAsync).
  2. Runner CLI (mjs-unit <fichiers>) : importe les fichiers de test, exécute, affiche un rapport, code de sortie ≠ 0 si échec.
  3. Resolver ESM : exécute sous Node les dist/ à imports sans extension (convention moduleResolution: bundler des modules @mostajs) — sans ce resolver, node échoue sur import './x'.

Installation

npm i -D @mostajs/mjs-unit
# module local non publié : npm i -D "@mostajs/mjs-unit@file:../chemin/mosta-mjs-unit"

How to use (pas à pas, dans n'importe quelle application)

  1. Installer le module en devDependency (voir ci-dessus).
  2. Créer un dossier test-scripts/ et y écrire des fichiers *.test.mjs (un test = test(name, fn) ; ne pas appeler run(), le runner s'en charge).
  3. Versionner un runner test-scripts/run-tests.sh qui (re)bâtit puis lance le CLI.
  4. Brancher package.json : "scripts": { "test": "bash test-scripts/run-tests.sh" }.
  5. Lancer : npm test (code de sortie ≠ 0 si un test échoue → utilisable en CI).
// test-scripts/api.test.mjs — test d'unité + test web, dans la même suite
import { test, equal, ok } from "@mostajs/mjs-unit";
import { createHttpTester, waitForEvent } from "@mostajs/mjs-unit/web";
import { app } from "../dist/app.js";            // votre app Express / handler natif

const api = createHttpTester(app);

test("GET /healthz → 200", async () => {
  const res = await api.get("/healthz");
  equal(res.status, 200);
  ok(res.body.status === "ok");
});
# test-scripts/run-tests.sh
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")/.."
npm run build >/dev/null
node node_modules/@mostajs/mjs-unit/bin/cli.mjs test-scripts/*.test.mjs

Besoin d'un profil d'environnement (DB de test, secrets…) avant d'importer le dist/ ? Fixez-le avant les imports via un import dynamique : process.env.APP_ENV = "TEST"; const { app } = await import("../dist/app.js"); (les import statiques sont hoistés, donc exécutés avant le code du module).

Écrire un test (test-scripts/mon.test.mjs)

import { test, expect, ok } from "@mostajs/mjs-unit";
import { maFonction } from "../dist/lib/ma-fonction.js"; // le dist peut avoir des imports sans extension

test("addition", () => expect(maFonction(2, 2)).toBe(4));
test("async", async () => { ok(await maFonction.async()); });

Ne pas appeler run() dans le fichier : le runner s'en charge (les cas enregistrés via test() sont exécutés groupés par fichier).

Lancer

mjs-unit test-scripts/*.test.mjs          # via le bin
# ou, programmatique :
node --import @mostajs/mjs-unit/register test-scripts/mon.test.mjs   # + appeler run() soi-même

Runner versionné conseillé (test-scripts/run-tests.sh) :

#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")/.."
npm run build >/dev/null
node node_modules/@mostajs/mjs-unit/bin/cli.mjs test-scripts/*.test.mjs

API

| Fonction | Rôle | |---|---| | test(name, fn) / test.skip(...) | Enregistre un cas (sync ou async) | | describe(group, body) | Préfixe les cas du groupe | | expect(v).toBe/toEqual/toBeTruthy/toBeFalsy/toContain | Assertions fluides | | ok/equal/deepEqual(...) | Assertions directes | | throwsAsync/doesNotThrowAsync(fn) | Vérifie qu'une promesse (ne) lève (pas) | | run(label?) | Exécute les cas en attente → {passed, failed, skipped} (appelé par le CLI) |

Zéro dépendance runtime ; @types/node en dev uniquement.

Tests web (@mostajs/mjs-unit/web)

Moteur générique pour tester des applications HTTP et événementielles — sans supertest, jest ni client socket dans le framework. Toujours zéro dépendance (uniquement node:http/node:net).

| Fonction | Rôle | |---|---| | startServer(target) | Démarre un serveur HTTP éphémère (port 0) autour d'un http.Server, d'un RequestListener ou d'une app Express → { url, port, close() } | | createHttpTester(target) | Client HTTP façon supertest : get/post/put/del/request{ status, headers, body }. target = URL d'un serveur démarré ou handler/serveur (éphémère par requête) | | waitForEvent(emitter, name, { timeout }) | Attend un événement sur tout émetteur (EventEmitter, client Socket.io, ws…) — teste le temps réel |

import { test, equal, ok } from "@mostajs/mjs-unit";
import { createHttpTester, startServer, waitForEvent } from "@mostajs/mjs-unit/web";

// HTTP : éphémère par requête (app Express ou handler natif (req,res)=>…)
const api = createHttpTester(app);
test("login", async () => {
  const res = await api.post("/login", { username: "admin", password: "admin" });
  equal(res.status, 200);
  ok(res.body.token);
});

// Temps réel : serveur durable + attente d'événement (ex. Socket.io)
test("push", async () => {
  const srv = await startServer(httpServer);          // serveur partagé
  const client = ioClient(srv.url);                   // socket.io-client fourni par l'app
  const received = waitForEvent(client, "new_ticket");
  await createHttpTester(srv.url).post("/api/tickets", { serviceType: "general" });
  const evt = await received;
  ok(evt.ticket);
  client.close();
  await srv.close();
});

Le client socket (socket.io-client, ws…) reste fourni par l'application : mjs-unit ne l'embarque pas, pour préserver le zéro-dépendance. waitForEvent fonctionne avec n'importe quel émetteur exposant on (idéalement once/off).