├── .nvmrc ├── .husky ├── pre-commit └── commit-msg ├── .commitlintrc ├── docs ├── summary.png └── annotation.png ├── .prettierrc ├── .editorconfig ├── .gitignore ├── test ├── resources │ ├── sample-tests │ │ ├── broken.test.js │ │ ├── skip.test.js │ │ └── nested.test.js │ └── expected.md ├── e2e │ └── compare.sh └── package-tests │ └── path.test.js ├── .eslintrc ├── .github ├── dependabot.yml └── workflows │ ├── notify-release.yml │ ├── check-linked-issues.yml │ ├── ci.yml │ └── release.yml ├── README.md ├── LICENSE ├── package.json └── index.js /.nvmrc: -------------------------------------------------------------------------------- 1 | 19 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | npx lint-staged 2 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | npx --no -- commitlint --edit $1 2 | -------------------------------------------------------------------------------- /.commitlintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "@commitlint/config-conventional" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /docs/summary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nearform/node-test-github-reporter/HEAD/docs/summary.png -------------------------------------------------------------------------------- /docs/annotation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nearform/node-test-github-reporter/HEAD/docs/annotation.png -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "singleQuote": true, 4 | "arrowParens": "avoid", 5 | "trailingComma": "none" 6 | } 7 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | end_of_line = lf 3 | insert_final_newline = true 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .eslintcache 3 | 4 | # JetBrains IDEs 5 | .idea 6 | # Visual Studio Code 7 | .vscode 8 | 9 | # OS X 10 | .DS_Store 11 | -------------------------------------------------------------------------------- /test/resources/sample-tests/broken.test.js: -------------------------------------------------------------------------------- 1 | import { it } from 'node:test' 2 | 3 | it('calls a nonexistent method', () => { 4 | // eslint-disable-next-line no-undef 5 | nonexistentMethod() 6 | }) 7 | -------------------------------------------------------------------------------- /test/resources/sample-tests/skip.test.js: -------------------------------------------------------------------------------- 1 | import { describe, it } from 'node:test' 2 | import assert from 'node:assert' 3 | 4 | describe('behavior', () => { 5 | it.skip('skipped test', () => { 6 | assert.strictEqual(1, 2) 7 | }) 8 | }) 9 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["eslint:recommended", "plugin:prettier/recommended"], 3 | "env": { 4 | "node": true, 5 | "es2021": true 6 | }, 7 | "parserOptions": { 8 | "ecmaVersion": 2021, 9 | "sourceType": "module" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: / 5 | schedule: 6 | interval: weekly 7 | - package-ecosystem: github-actions 8 | directory: / 9 | schedule: 10 | interval: weekly 11 | -------------------------------------------------------------------------------- /test/resources/sample-tests/nested.test.js: -------------------------------------------------------------------------------- 1 | import assert from 'node:assert' 2 | import { describe, it } from 'node:test' 3 | 4 | describe('module', () => { 5 | describe('function', () => { 6 | describe('behavior', () => { 7 | it('asserts 1 === 1', () => { 8 | assert.strictEqual(1, 1) 9 | }) 10 | 11 | it('fails', () => { 12 | assert.strictEqual(1, 2) 13 | }) 14 | }) 15 | }) 16 | }) 17 | -------------------------------------------------------------------------------- /.github/workflows/notify-release.yml: -------------------------------------------------------------------------------- 1 | name: Notify release 2 | 'on': 3 | workflow_dispatch: 4 | schedule: 5 | - cron: 30 8 * * * 6 | release: 7 | types: 8 | - published 9 | issues: 10 | types: 11 | - closed 12 | jobs: 13 | setup: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: nearform-actions/github-action-notify-release@v1 17 | permissions: 18 | issues: write 19 | contents: read 20 | -------------------------------------------------------------------------------- /.github/workflows/check-linked-issues.yml: -------------------------------------------------------------------------------- 1 | name: Check linked issues 2 | 'on': 3 | pull_request_target: 4 | types: 5 | - opened 6 | - edited 7 | - reopened 8 | - synchronize 9 | jobs: 10 | check_pull_requests: 11 | runs-on: ubuntu-latest 12 | name: Check linked issues 13 | steps: 14 | - uses: nearform-actions/github-action-check-linked-issues@v1 15 | id: check-linked-issues 16 | with: 17 | exclude-branches: release/**, dependabot/** 18 | permissions: 19 | issues: read 20 | pull-requests: write 21 | -------------------------------------------------------------------------------- /test/e2e/compare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # Function to replace test duration with 0 5 | remove_variables() { 6 | echo "$1" | sed -E 's/[0-9]+ms/0ms/g' 7 | } 8 | 9 | # Create temporary file to hold test summary 10 | export GITHUB_STEP_SUMMARY=$(mktemp) 11 | 12 | # Run sample tests and generate the report, ignoring errors 13 | node --test --test-reporter ./index.js ./test/resources/sample-tests || true 14 | 15 | # Compare with expected results 16 | report=$(cat $GITHUB_STEP_SUMMARY) 17 | expected=$(cat ./test/resources/expected.md) 18 | diff <(remove_variables "$report") <(remove_variables "$expected") 19 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Continuous Integration 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | 9 | jobs: 10 | test: 11 | name: Lint and test 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v6 15 | - uses: actions/setup-node@v6 16 | with: 17 | node-version-file: '.nvmrc' 18 | - run: | 19 | npm ci 20 | npm run lint 21 | npm test 22 | 23 | automerge: 24 | name: Merge dependabot's PRs 25 | needs: test 26 | runs-on: ubuntu-latest 27 | permissions: 28 | pull-requests: write 29 | contents: write 30 | steps: 31 | - uses: fastify/github-action-merge-dependabot@v3 32 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | semver: 6 | description: The semver to use 7 | required: true 8 | default: patch 9 | type: choice 10 | options: 11 | - patch 12 | - minor 13 | - major 14 | pull_request: 15 | types: [closed] 16 | 17 | jobs: 18 | release: 19 | runs-on: ubuntu-latest 20 | environment: production 21 | permissions: 22 | contents: write 23 | issues: write 24 | pull-requests: write 25 | id-token: write 26 | steps: 27 | - uses: nearform-actions/optic-release-automation-action@v4 28 | with: 29 | semver: ${{ github.event.inputs.semver }} 30 | commit-message: 'chore: release {version}' 31 | publish-mode: oidc 32 | build-command: npm ci 33 | -------------------------------------------------------------------------------- /test/package-tests/path.test.js: -------------------------------------------------------------------------------- 1 | import assert from 'node:assert' 2 | import { describe, it } from 'node:test' 3 | import { getRelativeFilePath, getSafePath } from '../../index.js' 4 | 5 | describe('File Path', () => { 6 | it('should prefix file:// to file path', () => { 7 | const expected = 'file:///path/to/file.js' 8 | const actual = getSafePath('/path/to/file.js') 9 | assert.equal(expected, actual) 10 | }) 11 | 12 | it('should not modify correctly constructed path', () => { 13 | const expected = 'file:///path/to/file.js' 14 | const actual = getSafePath('file:///path/to/file.js') 15 | assert.equal(expected, actual) 16 | }) 17 | 18 | it('should not error with file path without file:// prefix', () => { 19 | const expected = 'path/to/file.js' 20 | const actualUrl = getRelativeFilePath('/path/to/file.js') 21 | assert.equal(actualUrl, expected) 22 | }) 23 | }) 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # node-test-github-reporter 2 | 3 |  4 | 5 | A GitHub test reporter for the Node.js test runner 6 | 7 |  8 | 9 |  10 | 11 | ## Installation 12 | 13 | ```shell 14 | npm i -D node-test-github-reporter 15 | ``` 16 | 17 | ## Usage 18 | 19 | ```shell 20 | node --test --test-reporter node-test-github-reporter 21 | ``` 22 | 23 | You can use it in conjunction with another test report to also get the output in the logs: 24 | 25 | ```shell 26 | node --test --test-reporter spec --test-reporter-destination stdout --test-reporter node-test-github-reporter --test-reporter-destination stdout 27 | ``` 28 | 29 | [](https://www.nearform.com/contact/?utm_source=open-source&utm_medium=banner&utm_campaign=os-project-pages) 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 NearForm 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-test-github-reporter", 3 | "version": "1.3.1", 4 | "description": "A GitHub test reporter for the Node.js test runner", 5 | "main": "index.js", 6 | "type": "module", 7 | "scripts": { 8 | "lint": "eslint .", 9 | "test": "npm run test:compare && npm run test:package", 10 | "test:compare": "./test/e2e/compare.sh", 11 | "test:package": "node --test ./test/package-tests/**.test.js", 12 | "prepare": "husky" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git+https://github.com/nearform/node-test-github-reporter.git" 17 | }, 18 | "keywords": [ 19 | "test", 20 | "reporter", 21 | "github" 22 | ], 23 | "author": { 24 | "name": "Romulo Vitoi", 25 | "email": "romulo.vitoi@nearform.com" 26 | }, 27 | "license": "MIT", 28 | "bugs": { 29 | "url": "https://github.com/nearform/node-test-github-reporter/issues" 30 | }, 31 | "homepage": "https://github.com/nearform/node-test-github-reporter#readme", 32 | "dependencies": { 33 | "@actions/core": "^2.0.1", 34 | "error-stack-parser": "^2.1.4", 35 | "node-test-parser": "^3.0.0", 36 | "stack-utils": "^2.0.6" 37 | }, 38 | "devDependencies": { 39 | "@commitlint/cli": "^20.0.0", 40 | "@commitlint/config-conventional": "^20.0.0", 41 | "eslint": "^8.35.0", 42 | "eslint-config-prettier": "^10.0.1", 43 | "eslint-plugin-prettier": "5.5.4", 44 | "husky": "^9.0.11", 45 | "lint-staged": "^16.1.0", 46 | "prettier": "^3.0.3" 47 | }, 48 | "lint-staged": { 49 | "*.{js,jsx}": "eslint --cache --fix" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /test/resources/expected.md: -------------------------------------------------------------------------------- 1 |
| Passed | Failed | Skipped | Duration |
|---|---|---|---|
| 1 | 2 | 1 | 161ms |
7 | 8 | 9 | ``` 10 | nonexistentMethod is not defined 11 | ``` 12 | 13 | Stack: 14 | ``` 15 | TestContext.19 |(file://test/resources/sample-tests/broken.test.js:5:3) 16 | ``` 17 | 18 |
23 |62 |24 |61 |:x: function
25 |26 |60 |27 |59 |:x: behavior
28 |29 |58 |30 |35 |:white_check_mark: asserts 1 === 1
31 |32 | Test passed 33 |34 |36 |57 |:x: fails
37 |38 | 39 | 40 | ``` 41 | Expected values to be strictly equal: 42 | 43 | 1 !== 2 44 | 45 | ``` 46 | 47 | Stack: 48 | ``` 49 | 1 !== 2 50 | TestContext.56 |(file://test/resources/sample-tests/nested.test.js:12:16) 51 | async Promise.all (index 0) 52 | async Promise.all (index 0) 53 | ``` 54 | 55 |
66 |73 |67 |72 |:leftwards_arrow_with_hook: skipped test
68 |69 | Test skipped 70 |71 |
102 | ${content} 103 |104 |