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

@speqkit/plugin-allure

v0.5.0

Published

Allure results from the run's event stream. What `allure serve` reads.

Readme

@speqkit/plugin-allure

An Allure results directory, folded out of the run's event stream.

# speq.yaml
plugins:
  - allure

allure:
  output: allure-results        # relative to reports/, or an absolute path
speq run --reporter console,allure
allure serve .speq/reports/allure-results

Reporters are opt-in per run. --reporter names them; the default is console alone, so adding this plugin costs a registration and nothing else until a run asks for it.

What it writes, and what it does not

It writes results, not a report: <uuid>-result.json per test, <uuid>-container.json for setup and cleanup, the attachments beside them, and environment.properties / executor.json / categories.json when you have configured them. allure serve and allure generate turn that into the HTML — they are the tools your CI already runs, at the version your team already pinned.

Rendering the HTML here would mean vendoring somebody else's renderer inside a plugin, frozen at whatever version we happened to bundle, and it still would not be the one on your build agent. If what you want is a report that opens with a double click and needs no second tool, that is @speqkit/plugin-html, which is ours.

Where it writes, and why there

reports/allure-results — the stable directory, not reports/<runId>/.

A workflow names one fixed path and cannot interpolate a run id it will not learn until the step has already finished:

- run: speq run --env ci --reporter console,allure
- run: allure generate .speq/reports/allure-results -o allure-report --clean
- uses: actions/upload-artifact@v4
  if: always()
  with:
    name: allure-report
    path: allure-report

It also matters more here than it does for a file: allure serve takes a directory as an argument, and a person typing that wants to type the same one every time.

clean is on by default, because Allure reads a whole directory as one run and a stale result from yesterday would appear in today's report as a test that passed. The sweep is by pattern*-result.json, *-container.json, *-attachment.*, and the three named files. The output directory is a path out of your config file, and rm -rf on one of those is not something this plugin will do; a stray file in there survives, which is the correct failure mode.

How a run maps onto Allure's model

| speq | Allure | Why | | --- | --- | --- | | passed | passed | | | failed | failed | The system under test answered, and the answer was wrong. | | error | broken | It never answered at all. | | skipped | skipped | The reason the test gives becomes the status message. | | a step | a step, nested by parentId | A loop shows its iterations underneath it. | | an assertion | a step under the step it names | It is the leaf somebody opens a failing test to read. | | a suite's own setup | befores on the suite container | JUnit has nowhere to put this and drops it. | | a tag | a tag label | The same set --tags selects on. | | a cases row | a subSuite label plus parameters | What tells two rows of one table apart. | | an artifact | an attachment, copied in | Named by extension, because that is what picks the viewer. |

meta is read twice over. owner, severity, feature, story, epic, package and layer become the labels Allure groups and filters on; issue, tms and links become links a reader can click; everything else becomes a parameter, so a key this plugin was never taught about is still in the report rather than silently dropped. Add your own promotions with allure.labels:

allure:
  labels:
    squad: parentSuite     # meta key -> Allure label

Rebuilding a report you did not run

speq report --run 0f1c --reporter allure

Like every reporter here, it reads the event stream and nothing else — so a reports/ directory downloaded out of CI re-renders locally without rerunning a thing.

One honest limit, and it is about time. Allure's timeline wants absolute instants; the stream carries exactly one, run.started.at, and everything else is a duration. So the fold anchors on that instant and adds its own elapsed time as each event arrives. On a live run that is the truth. On a replay the events arrive all at once, so durations and order are exact and the stagger is lost — every test starts at the instant the original run did. The alternative was stamping the replay's own wall clock, which would produce a report claiming a run happened this afternoon when it happened in CI last week.

An attachment can only be carried across if the run wrote it: the event says how many bytes there were and never what they are. A run with no report directory, or one whose reports/ was cleaned in between, has nothing to copy, and the reporter says how many it could not find rather than writing a link to nothing.

The Environment panel

The two things that tell two red runs apart:

allure:
  environment:
    base url: ${env:BASE_URL}
    branch: ${env:GITHUB_REF_NAME}
  executor:
    name: GitHub Actions
    type: github
    buildUrl: ${env:GITHUB_SERVER_URL}/${env:GITHUB_REPOSITORY}/actions/runs/${env:GITHUB_RUN_ID}

The run id and the --env layer are written in already. Values are escaped the way java.util.Properties reads them back, which matters the moment a base URL has a port in it.

Categories

Allure's own rules for bucketing failures, so a known flake is not read as a new break:

allure:
  categories:
    - name: Environment down
      matchedStatuses: [broken]
      messageRegex: '.*ECONNREFUSED.*'

History

historyId is derived from the suite and the test name, and from nothing else — not the run id, not the order, not a duration. Copy the previous report's history/ directory into the results directory before generating, the way every Allure adapter asks you to, and the trend is there.