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

cletus

v1.0.4

Published

Portable test runner for browser and server!

Downloads

8

Readme

Cletus

A zero-dependency test runner for JavaScript that you can trust. The name Cletus comes from Greek, meaning "called forth" or "summoned" - exactly what this library does with your tests.

Why Cletus Exists

In a world where software dependencies can be compromised and supply chains attacked, Cletus takes a different approach: no dependencies. Every line of code is readable, understandable, and auditable. Simple is safe because you can read the entire source code in a few minutes and know exactly what runs in your application.

Trust is earned through transparency. Cletus is small enough to review, simple enough to understand, and powerful enough to test your code effectively.

Installation

npm install cletus

Or simply copy the single cletus.js file into your project. It's that simple.

Getting Started in the Browser

Cletus works beautifully in the browser without any build tools or bundlers. Create an HTML file and start testing:

<!DOCTYPE html>
<html>
<head>
  <title>My Tests</title>
</head>
<body>
  <h1>Test Results</h1>
  <pre id="output"></pre>

  <script type="module">
    import { test, describe, it, waitForCompletion } from './cletus.js';

    // Write your tests
    test('addition works', () => {
      const result = 2 + 2;
      if (result !== 4) {
        throw new Error(`Expected 4 but got ${result}`);
      }
    });

    describe('String operations', () => {
      it('concatenates strings', () => {
        const greeting = 'Hello' + ' ' + 'World';
        if (greeting !== 'Hello World') {
          throw new Error('String concatenation failed');
        }
      });
    });

    // Wait for tests to complete and display results
    const results = await waitForCompletion();
    document.getElementById('output').textContent =
      `Passed: ${results.summary.passed}\n` +
      `Failed: ${results.summary.failed}\n` +
      `Total: ${results.summary.total}`;
  </script>
</body>
</html>

Open this HTML file in any modern browser and see your tests run immediately. No server required, no build step needed.

Writing Tests

Basic Tests

Tests pass when they don't throw errors. It's that simple:

import { test } from './cletus.js';

test('objects can be created', () => {
  const obj = { name: 'Alice', age: 30 };
  if (!obj.name) {
    throw new Error('Object creation failed');
  }
});

Using Assertions

While Cletus doesn't include an assertion library (keeping it dependency-free), you can use the browser's built-in console.assert:

test('using console.assert', () => {
  const value = 10;
  console.assert(value > 5, 'Value should be greater than 5');
  console.assert(value < 20, 'Value should be less than 20');
});

Or create simple helper functions:

function assertEqual(actual, expected, message) {
  if (actual !== expected) {
    throw new Error(message || `Expected ${expected} but got ${actual}`);
  }
}

test('with helper function', () => {
  assertEqual(5 * 5, 25, 'Multiplication should work');
});

Asynchronous Tests

Modern JavaScript is asynchronous. Cletus handles async tests naturally:

test('fetch data from API', async () => {

  const response = await fetch('/api/data');
  const data = await response.json();

  if (!data.success) {
    throw new Error('API returned unsuccessful response');
  }

});

test('using promises directly', () => {
  return fetch('/api/status')
    .then(response => response.json())
    .then(data => {
      if (data.status !== 'healthy') {
        throw new Error('Service is not healthy');
      }
    });
});

Organizing Tests

Group related tests together for better organization:

import { describe, it } from './cletus.js';

describe('Calculator', () => {
  it('adds numbers', () => {
    if (1 + 1 !== 2) throw new Error('Addition failed');
  });

  it('multiplies numbers', () => {
    if (3 * 4 !== 12) throw new Error('Multiplication failed');
  });

  describe('Division', () => {
    it('divides numbers', () => {
      if (10 / 2 !== 5) throw new Error('Division failed');
    });

    it('handles division by zero', () => {
      const result = 10 / 0;
      if (!isFinite(result)) throw new Error('Should handle infinity');
    });
  });
});

Detecting When Tests Complete

Cletus provides multiple ways to know when your tests are done:

Promise-based (Recommended for Modern Code)

import { test, waitForCompletion } from './cletus.js';

test('example 1', () => { /* ... */ });
test('example 2', () => { /* ... */ });

// Wait for all tests to complete
const results = await waitForCompletion();
console.log(`All done! ${results.summary.passed} tests passed`);

Callback-based

import { test, onComplete } from './cletus.js';

test('example 1', () => { /* ... */ });
test('example 2', () => { /* ... */ });

onComplete((results) => {
  console.log('Tests finished!', results.summary);
});

Getting Results Programmatically

Perfect for building custom test reporters or integrating with other tools:

import { test, getResults, getSummary } from './cletus.js';

test('my test', () => { /* ... */ });

// Later, get the results
setTimeout(() => {
  const results = getResults();  // Full results with all output
  const summary = getSummary();  // Just the statistics

  // Build your own custom report
  console.log(JSON.stringify(results, null, 2));
}, 100);

Test Options

Skipping Tests

Temporarily disable tests without deleting them:

test('not ready yet', { skip: true }, () => {
  // This won't run
  throw new Error('This test is skipped');
});

Todo Tests

Mark tests for future implementation:

test('future feature', { todo: true }, () => {
  // This runs but won't fail your test suite
  throw new Error('Not implemented');
});

Subtests

Create tests within tests for better organization:

test('user management', async (t) => {
  const user = { name: 'Alice', email: '[email protected]' };

  await t.test('can create user', () => {
    if (!user.name) throw new Error('User needs a name');
  });

  await t.test('has valid email', () => {
    if (!user.email.includes('@')) {
      throw new Error('Invalid email format');
    }
  });
});

Running Multiple Test Suites

The reset() function allows you to run multiple independent test suites:

import { test, waitForCompletion, reset } from './cletus.js';

// First test suite
test('suite 1 test', () => { /* ... */ });
await waitForCompletion();

// Reset and run another suite
reset();
test('suite 2 test', () => { /* ... */ });
await waitForCompletion();

Node.js Compatibility

While Cletus is designed with the browser in mind, it works perfectly in Node.js too. The same code runs in both environments without modification. Use it in Node.js for server-side testing, CLI tools, or anywhere else JavaScript runs:

node my-tests.js

The API is identical, and the zero-dependency philosophy means it works with any Node.js version that supports ES modules.

Simple Examples for Learning

Testing a Shopping Cart

describe('Shopping Cart', () => {
  it('starts empty', () => {
    const cart = [];
    if (cart.length !== 0) {
      throw new Error('Cart should start empty');
    }
  });

  it('can add items', () => {
    const cart = [];
    cart.push({ item: 'apple', price: 1.00 });

    if (cart.length !== 1) {
      throw new Error('Cart should have one item');
    }
  });

  it('calculates total', () => {
    const cart = [
      { item: 'apple', price: 1.00 },
      { item: 'banana', price: 0.50 }
    ];

    const total = cart.reduce((sum, item) => sum + item.price, 0);

    if (total !== 1.50) {
      throw new Error(`Expected total 1.50 but got ${total}`);
    }
  });
});

Testing DOM Manipulation

describe('DOM operations', () => {
  it('can create elements', () => {
    const div = document.createElement('div');
    div.textContent = 'Hello';

    if (div.textContent !== 'Hello') {
      throw new Error('Failed to set text content');
    }
  });

  it('can find elements', () => {
    document.body.innerHTML = '<div id="test">Test</div>';
    const element = document.getElementById('test');

    if (!element) {
      throw new Error('Could not find element');
    }
  });
});

Custom Reporter

Stylesheet


:root {
  --test-text-color-primary: DarkOrange;
  --test-text-color-pass: DarkSlateGray;
  --test-text-color-fail: OrangeRed;
  --test-text-color-error: FireBrick;
}

.test-results {

  h1,h2,h3,h4,h5,h6 {
    color: var(--test-text-color-primary);
    margin-bottom: 1rem;
  }

  .test {

    padding: 0.5rem;
    margin-bottom: 1rem;

    &.test-pass {
      color: var(--test-text-color-pass);
    }

    &.test-fail {
      color: var(--test-text-color-fail);
    }

    &.test-error {
      color: var(--test-text-color-error);
      padding:1rem;

    }

    &.test-summary {
      color: var(--test-text-color-pass);
    }

  }

}

HTML Element


<div id="results" class="test-results"></div>

Custom Reporter

const results = await waitForCompletion();
const testResultContainer = document.getElementById("results")
const detailsElement = document.createElement('ol');
testResultContainer.appendChild(detailsElement);

if(0){
  const summaryElement = document.createElement('pre');
  summaryElement.textContent = `Passed: ${results.summary.passed}\n` + `Failed: ${results.summary.failed}\n`;
  testResultContainer.appendChild(summaryElement);
}

class Reporter {

  suite(name){
    const element = document.createElement('h2');
    element.textContent = name;
    return element;
  }

  pass(message){
    const element = document.createElement('p');
    element.classList.add('test', 'test-pass');
    element.textContent = message;
    return element;
  }

  fail(message){
    const element = document.createElement('p');
    element.classList.add('test', 'test-fail');
    element.textContent = message;
    return element;
  }

  error(message){
    const element = document.createElement('p');
    element.classList.add('test', 'test-error');
    element.textContent = message;
    return element;
  }

  summary(message){
    const element = document.createElement('p');
    element.classList.add('test', 'test-summary');
    element.textContent = message;
    return element;
  }

  separator(){
    return document.createElement('hr');
  }
}

const reporter = new Reporter();

for( const result of results.output ){
  const resultElement = reporter[result.type](result.message, result.timestamp) ;
  detailsElement.appendChild(resultElement);
}

Philosophy

Cletus follows these principles:

  1. Zero Dependencies: No supply chain vulnerabilities, no hidden code
  2. Readability: Every line is clear and purposeful
  3. Simplicity: Do one thing well - run tests
  4. Transparency: Small enough to audit in minutes
  5. Trust Through Clarity: You can understand everything it does

The Power of Simple

In an era of complex build tools and massive dependency trees, Cletus proves that testing can be simple. When your test runner is just a few hundred lines of readable JavaScript, you don't need to trust strangers on the internet. You can read it, understand it, and know exactly what code runs in your application.

Simple is safe. Simple is powerful. Simple is trustworthy.

Contributing

Cletus is open source and we welcome contributions. The entire codebase is in a single file, making it easy to understand and modify. Whether you're fixing a bug or improving documentation, your help makes Cletus better for everyone.

License

MIT


Named after the Greek word meaning "called forth," Cletus summons your tests into action with transparency and simplicity. In a world of growing complexity, sometimes the most powerful tool is the one you can hold in your hand and understand completely.