angles-report-importer
v1.0.2
Published
Imports test reports (allure, junit) into the Angles dashboard as builds, screenshots and test executions.
Maintainers
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-importerOr run it without installing:
npx angles-report-importer --results ./allure-results --team my-team \
--environment ci --component webUsage
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.
POST /build— creates the build to get abuildId.POST /screenshot× N — uploads each attachment, recording the id Angles assigned. Skipped entirely for formats with no attachments.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.
- Implement
ReportFormat(name,description,detect,parse) undersrc/formats/. - 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 buildLicense
Apache-2.0
