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

testbotron

v0.0.4

Published

Declarative UI test authoring on top of Webotron.

Readme

testbotron

Declarative UI tests on top of Webotron.

Testbotron lets you describe browser tests as plain TypeScript objects today, with a DSL shape that is intentionally friendly to YAML and JSON later. It is useful when you want tests to read like durable test cases rather than hand-written browser scripts.

Features

  • Declarative test documents with reusable named locators
  • Navigation, waits, clicks, typing, fixed delays, screenshots, and HTML snapshots
  • Text, attribute, and snapshot assertions with string matchers
  • Per-assertion failure policies: continue, stopTest, and stopRun
  • JSON reports plus a small static HTML report viewer
  • Built on Webotron, so you still keep direct control of the browser configuration

Install

bun add testbotron webotron

webotron is a peer dependency. Testbotron uses it to launch and control the browser.

CLI

bunx testbotron --help
bunx testbotron run ./tests/example.yaml
bunx testbotron run ./tests/example.json --test "data url example" --json-report

Supported CLI options:

  • --chrome-path <path>
  • --test <name>
  • --headless
  • --headed
  • --user-data-dir <dir>
  • --report-dir <dir>
  • --open-report
  • --json-report
  • --html-report

Quick start

import { runTest, type TestbotronDocument } from "testbotron";

const document: TestbotronDocument = {
  version: 1,
  defaults: {
    browser: {
      headless: true,
    },
  },
  locators: {
    learnMoreLink: { css: "a" },
  },
  tests: [
    {
      name: "example.com exposes its learn more link",
      baseUrl: "https://example.com",
      steps: [
        {
          navigate: {
            url: "/",
            waitUntil: "domcontentloaded",
            timeoutMs: 15000,
          },
        },
        {
          waitFor: {
            exists: "@learnMoreLink",
            timeoutMs: 10000,
          },
        },
        {
          expect: {
            text: {
              target: "@learnMoreLink",
              equals: "Learn more",
            },
          },
        },
        {
          expect: {
            attribute: {
              target: "@learnMoreLink",
              name: "href",
              contains: "iana.org",
            },
          },
        },
      ],
    },
  ],
};

await runTest(document, {
  chromePath: "C:/Program Files/Google/Chrome/Application/chrome.exe",
  testName: "example.com exposes its learn more link",
  report: {
    outputDir: "reports",
  },
});

Core DSL

Each step is a one-key object, which keeps documents readable and simple to serialize:

steps: [
  { navigate: { url: "/", waitUntil: "domcontentloaded" } },
  { waitFor: { exists: "@searchBox", timeoutMs: 10000 } },
  {
    type: {
      target: "@searchBox",
      text: "solidjs",
      perCharacterDelayMs: 120,
    },
  },
  { click: { target: "@submitButton" } },
  { wait: 5000 },
  { screenshot: { path: "artifacts/results.png" } },
]

Current executable step support includes:

  • navigate
  • wait
  • waitFor.readyState
  • waitFor.exists
  • click
  • type
  • press
  • expect.text
  • expect.attribute
  • snapshotHtml
  • expect.snapshotHtml
  • screenshot

The DSL types already sketch additional future verbs, but the runner is still intentionally small in this early version.

Locators

Named locators make test steps easier to read and reuse:

locators: {
  searchBox: { css: "textarea[name='q']" },
  submitButton: { css: "input[name='btnK']" },
}
{ waitFor: { exists: "@searchBox" } }
{ click: { target: "@submitButton" } }

The broader DSL type model includes semantic locator shapes such as byRole, byText, and byLabel. The current executable runner slice supports CSS locators for the implemented browser actions and assertions.

Assertions

String-based assertions support:

  • equals
  • notEquals
  • contains
  • notContains
  • startsWith
  • endsWith
  • matches
{
  expect: {
    text: {
      target: "@heading",
      startsWith: "Dash",
    },
  },
}

Assertions default to stopTest, but you can change that at the document, test, or individual assertion level:

defaults: {
  assertions: {
    onFailure: "continue",
  },
}

HTML snapshots

Capture markup at one moment in time, then assert against that exact captured value later:

{
  snapshotHtml: {
    as: "learnMoreMarkup",
    target: "@learnMoreLink",
    mode: "outer",
  },
},
{
  expect: {
    snapshotHtml: {
      source: "@learnMoreMarkup",
      contains: "iana.org",
    },
  },
}

This is useful when you want reports to show the exact DOM fragment involved in a failure.

Reports

runTest() can write both machine-readable JSON and a simple HTML report:

await runTest(document, {
  chromePath,
  testName: "example.com exposes its learn more link",
  report: {
    outputDir: "reports",
    openHtml: true,
  },
});

Every step is recorded with status, timing, input, result, and failure metadata. Reports are still written when a test fails, including failures that stop the current test.

For multi-test documents, use runTests() to execute the full suite and honor stopRun assertion policies.

If you want report content without writing files, pass writeToFiles: false and use the returned artifacts strings:

const result = await runTest(document, {
  chromePath,
  testName: "example.com exposes its learn more link",
  report: {
    writeToFiles: false,
  },
});

console.log(result.artifacts?.json);
console.log(result.artifacts?.html);

Browser configuration

Browser startup options are passed through to Webotron:

await runTest(document, {
  chromePath,
  testName,
  browser: {
    headless: false,
    userDataDir: "./.tmp-browser-profile",
  },
});

Pass userDataDir when you want repeat runs to reuse a browser profile, or use Webotron profile options when you need isolated browser state.

Status

Testbotron is early and deliberately small. The current focus is a clear declarative model, reliable reporting, and a compact set of browser primitives that are easy to grow without turning the DSL into a disguised programming language.