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

@burojs/testing

v0.5.0

Published

Buro: test-time tools — checkApp and describeScreen

Readme

@burojs/testing

Test-time tools for buro apps: describeScreen and checkApp. Not for application code — import it from your tests.

Source, in this package, is a screen source: a name a screen reads (record, values, scope, route, user, and the screen's with names), which describeScreen's sources option fills with fixtures. A configuration source — a JSON or YAML document a host loads with @burojs/config — and its SourcePolicy are a different thing; checkApp reports what such a source's layer did through that layer's status.

pnpm add -D @burojs/testing

It imports no test runner: both functions return plain values to assert on with any runner. The examples below use Vitest.

describeScreen(resource, mode, { sources?, permissions?, ref? })

Compiles and plans one record screen (show, edit or create) of a resource with every source ready, and returns:

  • visibleKeys(): the keys of the keyed nodes that are not absent, in tree order, and nodeByKey(key): one planned node (state, reason, its children…);
  • fields: each field's status (active, readonly, inactive, pending);
  • texts: every text slot, with its bundle key and its default;
  • plan: the whole ScreenPlan that planScreen returned, its header and body trees included, for what the helpers above do not answer;
  • issues: why the screen could not be compiled — screen-limit when it nests too deep once types' extend entries are appended, with an empty plan. Empty otherwise.

Options:

  • sources supplies fixture values by source name: record, values, scope, and the screen's own with sources. Source here is a screen's data source — not a configuration source (@burojs/config), and not a layer runtime's source. A source without a fixture is ready with the value null; in show and edit, values defaults to the record fixture. In create mode there is no record, so a record fixture is ignored.
  • permissions is a PermissionMap. The default allows everything, unlike planScreen itself, which plans every requires panel absent when no map is passed (fail closed). Pass a map to test a gated panel.
  • ref is the resource's canonical ref, for a portable resource value (what a configuration source committed), which does not carry one: its texts then key as resources.<canonical key>.…, as the runtime's do. A resource handle's own ref wins.
import type { ResourcePortableValue } from '@burojs/core';
import { describeScreen } from '@burojs/testing';
import { expect, it } from 'vitest';
import { orders } from '../src/resources/orders.js';

it('shows the shipping panel once the order is paid', () => {
  const draft = describeScreen(orders, 'show', { sources: { record: { status: 'draft' } } });
  expect(draft.visibleKeys()).not.toContain('shipping');
  const paid = describeScreen(orders, 'show', { sources: { record: { status: 'paid' } } });
  expect(paid.visibleKeys()).toContain('shipping');
  expect(paid.issues).toEqual([]);
});

it('plans the catalog screen a configuration source committed', async () => {
  // `app`: your app runtime (`defineApp(…)`), with the configuration source registered and loaded.
  await app.ready;
  const ref = { namespace: 'json', id: 'catalog' };
  const value = app.runtime.getSnapshot().getProjection({ kind: 'resource', ref })?.value;
  const screen = describeScreen(value as ResourcePortableValue, 'show', { ref });
  expect(screen.texts.map((text) => text.key)).toContain('resources.json:catalog.nodes.main.title');
});

describeScreen is how a test sees a tree without rendering it.

With no permissions option describeScreen treats everything as granted, so a field guarded by requires reads visible. describeAvailability and the runtime hide guarded fields when there is no permission map; pass a map to test the guarded reading.

describePageScreen(page, { sources?, permissions?, blocks?, blockData? })

The same description of a custom page's body (defineCustomPage({ …, body }), or a page read back from app.registry.customPages), planned in show mode with no record. Pass the handles of the blocks the page places in blocks; a block it cannot resolve compiles denied.

await checkApp(app, { i18n?, components? })

Reports the screen and declaration diagnostics of an app in one call, as { code, severity, location, message, locale?, key? }[], in a stable order. app is any app runtime — what defineApp returns, or definition.createRuntime().

import { checkApp } from '@burojs/testing';

it('has no diagnostics', async () => {
  expect(await checkApp(app)).toEqual([]);
});

What it reports:

  • An app whose ready rejects: its compile errors.

  • Otherwise, once every registered source has settled, required or not (app.runtime.whenSettled(); a load still in flight is awaited, and a source never loaded is not loaded). checkApp waits for every one of them with no timeout, so a source whose load never resolves hangs it, and the test with it until the runner's own timeout; a test that registers such a source should not call checkApp until the load has settled:

    • the screen checker's issues over the committed snapshot — the layout.*, fields.*, create.*, ref.*, relation.*, screen.*, access.can-in-when and type.* codes. A committed declaration has no errors, so these are its warnings (layout.empty);
    • the diagnostics of every layer status in error (app.runtime.getLayerStatuses()). A granted layer that fails is left out while your code commits, so its diagnostics live only on its status. A granted layer's diagnostics are in their public form;
    • the diagnostics of every rejected app.use(...) (app.rejectedUses): its errors and its own warnings. use resolves a rejection as { status: 'rejected', diagnostics } without throwing, and ready does not reject on it, so the resources it carried are simply missing. A later use under the same contribution id that commits clears it; for a use without an id, a later use that commits every declaration it made does.
  • Otherwise, with i18n: registry, also the translation coverage of every declared text slot: resource, chrome, field, option, enum value, enum fallback and action labels, node titles and descriptions, and check messages. A label declared as '' is no slot. registry is the app's own locale registry (createLocaleRegistry({ primary }) from @burojs/i18n-core, or anything with its primary() and buildResources()): the bundles checked are what buildResources() returns, and the primary locale — the one whose text is the default in code — is registry.primary(). Pass the same registry the app builds its facade from, so the check cannot disagree with the app about which locale is primary. To probe an empty locale, register an empty bundle for it on a fresh registry.

    • i18n.missing (warning, with locale and key): a non-primary locale covers the slot at no key of its lookup chain. key is the entry key of that chain (resources.clients.fields.status, not its .label).
    • i18n.object (error, with locale and key), in any locale: an object at a key the slot reads that is not an entry carrying its leaf (a locale map in a bundle, for one). An entry holding only entry keys (label, title, description, empty, doc, options, placeholder), such as a doc-only field entry, is not one: its slot counts as missing until the leaf is there.

    The keys and their chains are the table in docs/i18n-guide.md. Text a host reads with t() itself, outside any declaration, is not a slot.

  • With components (the host's <BuroProvider components> map), also the error screen.override-removed for each record override key — record.<show|edit|create>.<resource>. Record overrides were removed in P6 and such a component is never rendered; lay the screen out with a frame (views.<mode>.frame) or <RecordScreen frame>. Other keys are ignored.

// The app's i18n module builds its registry: createLocaleRegistry({ primary }) plus its contributions.
import { buildLocaleRegistry } from '../src/i18n.js';

const reported = await checkApp(app, { i18n: buildLocaleRegistry() });
expect(reported.filter((entry) => entry.code === 'i18n.missing')).toEqual([]);

A labelled action's slot is covered only by the resource's own entry (resources.<r>.actions.<name> or its .label): the action button shows the declared label before resources._ and common, so those never translate it.

What it does not report:

  • suspended statuses (a layer waiting for a transform target) and their warnings;
  • compile warnings outside the screen checker (missing-transform-target, source.priority-clamped);
  • what checks report at run time (check.parseError, check.exception): a check is code the compiler never sees;
  • definition-time errors (fields.bad-name on an authored object, source.reserved-key, i18n.inline-map in a define* call), which throw before an app exists;
  • a flow's argument (args) labels: they are not text slots yet, so a missing translation there is not reported. (A flow's confirm, notify, check messages and form field labels are slots, under resources.<r>.actions.<name>.)

location reads <resource> <mode>.<path>. For example, clients show.body[1].tabs[audit] names a keyed node by its key, a field leaf by its name, and other nodes by index, as it names an element of a fields list (clients fields[1]). A declaration that never committed — a rejected compile, a left-out layer — has no value to read keys from, so its nodes are named by index (clients show.body[1].children[0]). A target that is not a resource reads <kind> <ref> <path>.

@burojs/testing/react: renderBlock and fakeData

Renders a block view alone, the way a placement renders it, without an app:

import { renderBlock, fakeData } from '@burojs/testing/react';
import { kpiView } from '../src/blocks/kpi-view';
import { kpi } from '../src/blocks/kpi';

await renderBlock(kpiView, {
  props: { userId: 'u1' },
  data: fakeData(kpi, { total: { n: 9 } }),
  messages: { title: 'Total' },
});
  • renderBlock(implementation, { props?, data?, messages?, wrapper? }) takes the implementBlock(...) result (never an id). It validates props through the block's schemas — literal defaults applied, the view receives each schema's output — and rejects with code: 'block.prop-invalid' when a prop fails. A load implementation is awaited. The view's t(key) returns messages[key], or the key.
  • fakeData(block, entries) returns a frozen object of data entry values; an entry the block does not declare throws a TypeError.

The subpath needs react, @burojs/react and @testing-library/react, declared as optional peer dependencies: the root @burojs/testing entry (checkApp, describeScreen) needs none of them.