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

angles-report-importer

v1.0.2

Published

Imports test reports (allure, junit) into the Angles dashboard as builds, screenshots and test executions.

Readme

angles-report-importer

Imports test reports into the Angles dashboard as builds, screenshots and test executions.

Supported formats:

| Format | Input | Screenshots | | --- | --- | --- | | allure | An allure-results directory (*-result.json / *-container.json) | Yes | | junit | A JUnit XML file, or a directory of them | No — the format has no attachments |

Install

npm install --save-dev angles-report-importer

Or run it without installing:

npx angles-report-importer --results ./allure-results --team my-team \
  --environment ci --component web

Usage

angles-import \
  --results ./allure-results \
  --url https://angles.example.com \
  --api-key "$ANGLES_API_KEY" \
  --team my-team \
  --environment ci \
  --component web \
  --name "build ${BUILD_NUMBER}" \
  --platform-name linux --browser-name chrome

--url defaults to ANGLES_URL (or http://localhost:3000) and --api-key to ANGLES_API_KEY. The team, environment and component must already exist in Angles, and the component must belong to the team.

The format is detected from the directory contents, so --format is only needed when detection is ambiguous. Run angles-import --help for the full option list.

Options

| Option | Effect | | --- | --- | | --format <name> | allure or junit. Detected automatically when omitted. | | --dry-run | Parses and maps everything, reports what would be sent, calls no endpoints. Needs no API key. | | --write-back | Records the Angles screenshot ids in the source report (allure only). | | --json | Prints the summary as json on stdout; progress goes to stderr, so it pipes cleanly. | | --concurrency <n> | Parallel screenshot uploads, default 4. | | --phase <name> | Angles phase name. |

Exit codes

| Code | Meaning | | --- | --- | | 0 | Everything imported. | | 1 | The import could not be done at all (bad credentials, unknown team, no results). | | 2 | The build was created but some attachments or executions failed; details are on stderr. |

How the import works

The API forces the order: a screenshot upload needs a buildId, and an execution step can only reference a screenshot that already exists.

  1. POST /build — creates the build to get a buildId.
  2. POST /screenshot × N — uploads each attachment, recording the id Angles assigned. Skipped entirely for formats with no attachments.
  3. POST /execution × N — one execution per test, steps carrying those screenshot ids.

Executions are posted sequentially on purpose: each triggers a read-modify-write of the build document to recalculate suite metrics, and parallel posts would make those writes contend. Angles recalculates build status as each execution lands, so nothing is needed to close the build off.

POST /build can accept executions inline, which would make this a single call — but steps could then not reference screenshots, since no build id exists at that point.

Status mapping

Angles derives an action's status from its steps and an execution's status from its actions, so the importer only ever sets step statuses.

| Allure | JUnit | Angles step | Resulting execution | | --- | --- | --- | --- | | passed | (no failure element) | PASS | PASS | | failed | <failure> | FAIL | FAIL | | broken | <error> | ERROR | ERROR | | skipped | <skipped> | INFO | SKIPPED | | unknown | — | ERROR | ERROR |

Both tools draw the same distinction between a failed assertion and an unexpected error, so broken/<error> map to ERROR rather than FAIL.

A test with no usable steps gets a single synthesised Result step carrying its outcome. For JUnit that is every test, since the format has no concept of a step.

Format details

Allure

| Allure | Angles | | --- | --- | | result | execution | | suite / parentSuite / testClass / package / feature label | suite (falls back to the component name) | | container befores | a Setup action | | result steps | an action named after the test | | container afters | a Teardown action | | nested steps | flattened into the action, names indented with ↳ | | step statusDetails.message / .trace | step actual / info | | step parameters | step info | | feature label | feature | | tag labels, severity | tags (severity as severity:<value>) | | host / browser / device labels | platforms (overridden by --platform-*) | | owner, story, fullName, uuid, historyId, links | meta |

Only image attachments are uploaded (png, jpeg, gif, webp, bmp, tiff); text and video attachments have nowhere to go in Angles.

An image attached to a step becomes that step's screenshot. An image attached to the test or a fixture rather than to a step — where most frameworks put a failure screenshot — is collected into a trailing Attachments action so it is still visible.

With --write-back, each uploaded attachment gains an anglesScreenshotId in the allure json. Fixture attachments live in the container file, so containers are rewritten too.

JUnit

Handles the variations that occur in practice: a <testsuites> root or a bare <testsuite>, nested suites, <skipped>/<failure>/<error> elements, and <system-out>/<system-err> at case or suite level.

| JUnit | Angles | | --- | --- | | <testcase> | execution, with one synthesised step | | classname attribute | suite (falls back to the suite name, then the file name) | | message / type attribute | step actual | | failure element text (including CDATA) | step info | | <system-out> / <system-err> | step info (case-level preferred over suite-level) | | <properties> | meta | | suite timestamp + case time | start / end |

JUnit records a duration per case but no start time, so cases are laid out end to end from the suite's timestamp. That keeps them ordered and gives Angles a sensible build duration.

Note that dots in meta keys are replaced with underscores (java.version becomes java_version): Angles stores meta as a Mongo map, which rejects dotted keys.

Adding a format

Formats are plugins behind a single interface. A parser produces the intermediate representation in src/core/model.ts and knows nothing about the Angles API; everything else — uploading, status derivation, field limits — is shared.

  1. Implement ReportFormat (name, description, detect, parse) under src/formats/.
  2. Add it to the list in src/formats/registry.ts.

Implement parse().writeBack only if the source files can carry the Angles screenshot ids back, as allure's can.

Programmatic use

import { AnglesClient, importReport, getFormat } from 'angles-report-importer';

const summary = await importReport({
  format: getFormat('junit'),
  resultsDirectory: './target/surefire-reports',
  client: new AnglesClient({ baseUrl: 'https://angles.example.com', apiKey: process.env.ANGLES_API_KEY }),
  build: { team: 'my-team', environment: 'ci', component: 'web', name: 'build 42' },
});

Development

npm install
npm test      # unit tests, no server required
npm run lint
npm run build

License

Apache-2.0