Skip to content

Commit 6f12978

Browse files
committed
Generate simple tap v14 output from jest test results
1 parent abed7dd commit 6f12978

8 files changed

Lines changed: 270 additions & 1 deletion

File tree

.github/workflows/build.yaml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
name: build
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
11+
jobs:
12+
build:
13+
runs-on: ubuntu-latest
14+
15+
strategy:
16+
matrix:
17+
node-version: [20, 21]
18+
19+
steps:
20+
- uses: actions/checkout@v4
21+
22+
- uses: actions/setup-node@v4
23+
with:
24+
node-version: ${{ matrix.node-version }}
25+
26+
- name: Install dependencies
27+
run: npm ci
28+
29+
- name: Build
30+
run: npm run build

.github/workflows/publish.yaml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# This script is automatically triggered when a tag corresponding to a new version is pushed
2+
# That will cause the build to be published to npm
3+
name: publish
4+
5+
on:
6+
push:
7+
tags: [v*]
8+
9+
permissions:
10+
contents: read # required for accessing repository contents
11+
12+
jobs:
13+
build:
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
- uses: actions/checkout@v4
18+
- uses: actions/setup-node@v4
19+
with:
20+
node-version: '20.7.0'
21+
registry-url: 'https://registry.npmjs.org'
22+
cache: 'npm'
23+
- run: npm ci --no-audit
24+
- env:
25+
NODE_AUTH_TOKEN: ${{ secrets.NPM_READWRITE_TOKEN }}
26+
run: npm publish

.github/workflows/release.yaml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Run this script manually to bump the version number and trigger a publish
2+
name: release
3+
4+
on:
5+
workflow_dispatch:
6+
inputs:
7+
level:
8+
description: 'Increment the version by the specified level. Level can be one of: major, minor, patch'
9+
required: true
10+
default: 'minor'
11+
type: choice
12+
options:
13+
- major
14+
- minor
15+
- patch
16+
17+
jobs:
18+
build:
19+
runs-on: ubuntu-latest
20+
21+
steps:
22+
- uses: actions/checkout@v4
23+
with:
24+
token: ${{ secrets.GH_ACCESS_TOKEN }}
25+
- uses: actions/setup-node@v4
26+
with:
27+
node-version: '20.7.0'
28+
registry-url: 'https://registry.npmjs.org'
29+
cache: 'npm'
30+
- run: npm version ${{ inputs.level }}
31+
- name: git config
32+
run: |
33+
git config user.name 'Warwick ✠'
34+
git config user.email warwick@globalworldwide.com
35+
- run: git push origin --follow-tags

.prettierrc.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"semi": true,
3+
"singleQuote": true,
4+
"printWidth": 100,
5+
"arrowParens": "always",
6+
"trailingComma": "all"
7+
}

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
# jest-tap-reporter
1+
# jest-reporter-tap
22
Test Anything Protocol reporter for Jest

index.mjs

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import { createWriteStream } from 'node:fs';
2+
import path from 'node:path';
3+
import YAML from 'yaml';
4+
5+
class TapWriter {
6+
#stream;
7+
#testCount = 0;
8+
9+
constructor(stream) {
10+
this.#stream = stream;
11+
}
12+
13+
version() {
14+
this.#stream.write(`TAP version 14\n`);
15+
}
16+
17+
testPoint(ok, description, directive, data) {
18+
this.#stream.write(`${ok ? 'ok' : 'not ok'} ${++this.#testCount} - ${description}`);
19+
if (directive) {
20+
this.#stream.write(` # ${directive}`);
21+
}
22+
this.#stream.write('\n');
23+
if (data) {
24+
this.#stream.write(' ---\n');
25+
for (const line of YAML.stringify(data).split('\n')) {
26+
this.#stream.write(` ${line}\n`);
27+
}
28+
this.#stream.write(' ...\n');
29+
}
30+
}
31+
32+
plan() {
33+
this.#stream.write(`1..${this.#testCount}\n`);
34+
}
35+
}
36+
37+
function formatErrorMessage(error) {
38+
// remove escape codes that jest is leaving in the error message
39+
return error?.replaceAll(/\x1b\[\d+\w/g, '');
40+
}
41+
42+
export default class TapReporter {
43+
constructor(globalConfig, reporterOptions, reporterContext) {
44+
this._globalConfig = globalConfig;
45+
this._options = reporterOptions;
46+
this._context = reporterContext;
47+
}
48+
49+
onRunComplete(_testContexts, results) {
50+
let stream = this._options.filePath
51+
? createWriteStream(this._options.filePath)
52+
: process.stdout;
53+
let writer = new TapWriter(stream);
54+
writer.version();
55+
56+
for (const suiteResult of results.testResults) {
57+
if (suiteResult.testExecError) {
58+
// suite failed altogether, treat this as a failed single test
59+
writer.testPoint(
60+
false,
61+
suiteResult.displayName ?? this.#relativePath(suiteResult.testFilePath),
62+
undefined,
63+
{
64+
code: suiteResult.testExecError.code,
65+
message: suiteResult.testExecError.message,
66+
stack: suiteResult.testExecError.stack,
67+
type: suiteResult.testExecError.type,
68+
},
69+
);
70+
} else {
71+
// suite passed, now iterate over individual tests
72+
for (const testResult of suiteResult.testResults) {
73+
switch (testResult.status) {
74+
case 'passed':
75+
writer.testPoint(true, testResult.fullName, undefined, undefined);
76+
break;
77+
case 'failed':
78+
writer.testPoint(false, testResult.fullName, undefined, {
79+
message: formatErrorMessage(testResult.failureMessages[0]) ?? 'Unknown failure',
80+
more: testResult.failureMessages.slice(1).map(formatErrorMessage),
81+
});
82+
break;
83+
case 'skipped':
84+
case 'pending':
85+
writer.testPoint(true, testResult.fullName, 'skip', undefined);
86+
break;
87+
case 'todo':
88+
writer.testPoint(false, testResult.fullName, 'todo', undefined);
89+
break;
90+
default:
91+
writer.testPoint(false, testResult.fullName, undefined, {
92+
message: `Unknown status ${testResult.status}`,
93+
});
94+
break;
95+
}
96+
}
97+
}
98+
}
99+
100+
writer.plan();
101+
102+
if (stream !== process.stdout) {
103+
stream.end();
104+
}
105+
}
106+
107+
getLastError() {
108+
return undefined;
109+
}
110+
111+
#relativePath(file) {
112+
return path.relative(this._globalConfig.rootDir, file);
113+
}
114+
}

package-lock.json

Lines changed: 27 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"name": "@globalworldwide/jest-reporter-tap",
3+
"version": "0.0.1",
4+
"description": "Test Anything Protocol reporter for Jest",
5+
"type": "module",
6+
"main": "index.mjs",
7+
"scripts": {
8+
"build": "echo \"no build specified\"",
9+
"test": "echo \"no test specified\""
10+
},
11+
"repository": {
12+
"type": "git",
13+
"url": "git+https://github.com/globalworldwide/jest-reporter-tap.git"
14+
},
15+
"keywords": [
16+
"jest",
17+
"tap",
18+
"tap-v14",
19+
"reporter"
20+
],
21+
"author": "Matthew Douglass <matthew@globalworldwide.com>",
22+
"license": "MIT",
23+
"bugs": {
24+
"url": "https://github.com/globalworldwide/jest-reporter-tap/issues"
25+
},
26+
"homepage": "https://github.com/globalworldwide/jest-reporter-tap#readme",
27+
"dependencies": {
28+
"yaml": "^2.4.0"
29+
}
30+
}

0 commit comments

Comments
 (0)