mirror of
https://github.com/dorny/test-reporter.git
synced 2025-12-15 13:57:09 +01:00
Add support for mocha-json
This commit is contained in:
parent
f285c4c6d7
commit
9b675bd55f
21 changed files with 1588 additions and 59 deletions
|
|
@ -123,6 +123,7 @@ jobs:
|
|||
# dotnet-trx
|
||||
# flutter-json
|
||||
# jest-junit
|
||||
# mocha-json
|
||||
reporter: ''
|
||||
|
||||
# Limits which test suites are listed:
|
||||
|
|
|
|||
40
__tests__/__outputs__/mocha-json.md
Normal file
40
__tests__/__outputs__/mocha-json.md
Normal file
|
|
@ -0,0 +1,40 @@
|
|||

|
||||
## <a id="user-content-r0" href="#r0">fixtures/mocha-json.json</a> ❌
|
||||
**7** tests were completed in **14ms** with **1** passed, **5** failed and **1** skipped.
|
||||
|Test suite|Passed|Failed|Skipped|Time|
|
||||
|:---|---:|---:|---:|---:|
|
||||
|[test/main.test.js](#r0s0)|1✔️|3❌||1ms|
|
||||
|[test/second.test.js](#r0s1)||1❌|1✖️|NaNms|
|
||||
|[test/test.js](#r0s2)||1❌||0ms|
|
||||
### <a id="user-content-r0s0" href="#r0s0">test/main.test.js</a> ❌
|
||||
**4** tests were completed in **1ms** with **1** passed, **3** failed and **0** skipped.
|
||||
|
||||
**Test 1**
|
||||
|Result|Test|Time|
|
||||
|:---:|:---|---:|
|
||||
|✔️|Passing test|0ms|
|
||||
|
||||
**Test 1 Test 1.1**
|
||||
|Result|Test|Time|
|
||||
|:---:|:---|---:|
|
||||
|❌|Exception in target unit|0ms|
|
||||
|❌|Failing test|1ms|
|
||||
|
||||
**Test 2**
|
||||
|Result|Test|Time|
|
||||
|:---:|:---|---:|
|
||||
|❌|Exception in test|0ms|
|
||||
### <a id="user-content-r0s1" href="#r0s1">test/second.test.js</a> ❌
|
||||
**2** tests were completed in **NaNms** with **0** passed, **1** failed and **1** skipped.
|
||||
|
||||
|Result|Test|Time|
|
||||
|:---:|:---|---:|
|
||||
|✖️|Skipped test|NaNms|
|
||||
|❌|Timeout test|10ms|
|
||||
### <a id="user-content-r0s2" href="#r0s2">test/test.js</a> ❌
|
||||
**1** tests were completed in **0ms** with **0** passed, **1** failed and **0** skipped.
|
||||
|
||||
**Array #indexOf()**
|
||||
|Result|Test|Time|
|
||||
|:---:|:---|---:|
|
||||
|❌|should return -1 when the value is not present|0ms|
|
||||
137
__tests__/__snapshots__/mocha-json.test.ts.snap
Normal file
137
__tests__/__snapshots__/mocha-json.test.ts.snap
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`mocha-json tests report from ./reports/mocha-json test results matches snapshot 1`] = `
|
||||
TestRunResult {
|
||||
"path": "fixtures/mocha-json.json",
|
||||
"suites": Array [
|
||||
TestSuiteResult {
|
||||
"groups": Array [
|
||||
TestGroupResult {
|
||||
"name": "Test 1",
|
||||
"tests": Array [
|
||||
TestCaseResult {
|
||||
"error": undefined,
|
||||
"name": "Passing test",
|
||||
"result": "success",
|
||||
"time": 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
TestGroupResult {
|
||||
"name": "Test 1 Test 1.1",
|
||||
"tests": Array [
|
||||
TestCaseResult {
|
||||
"error": Object {
|
||||
"details": "Error: Some error
|
||||
at Object.throwError (lib\\\\main.js:2:9)
|
||||
at Context.<anonymous> (test\\\\main.test.js:15:11)
|
||||
at processImmediate (internal/timers.js:461:21)",
|
||||
"line": 2,
|
||||
"message": "Some error",
|
||||
"path": "lib/main.js",
|
||||
},
|
||||
"name": "Exception in target unit",
|
||||
"result": "failed",
|
||||
"time": 0,
|
||||
},
|
||||
TestCaseResult {
|
||||
"error": Object {
|
||||
"details": "AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
|
||||
|
||||
false !== true
|
||||
|
||||
at Context.<anonymous> (test\\\\main.test.js:11:14)
|
||||
at processImmediate (internal/timers.js:461:21)",
|
||||
"line": 11,
|
||||
"message": "Expected values to be strictly equal:
|
||||
|
||||
false !== true
|
||||
",
|
||||
"path": "test/main.test.js",
|
||||
},
|
||||
"name": "Failing test",
|
||||
"result": "failed",
|
||||
"time": 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
TestGroupResult {
|
||||
"name": "Test 2",
|
||||
"tests": Array [
|
||||
TestCaseResult {
|
||||
"error": Object {
|
||||
"details": "Error: Some error
|
||||
at Context.<anonymous> (test\\\\main.test.js:22:11)
|
||||
at processImmediate (internal/timers.js:461:21)",
|
||||
"line": 22,
|
||||
"message": "Some error",
|
||||
"path": "test/main.test.js",
|
||||
},
|
||||
"name": "Exception in test",
|
||||
"result": "failed",
|
||||
"time": 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
"name": "test/main.test.js",
|
||||
"totalTime": undefined,
|
||||
},
|
||||
TestSuiteResult {
|
||||
"groups": Array [
|
||||
TestGroupResult {
|
||||
"name": null,
|
||||
"tests": Array [
|
||||
TestCaseResult {
|
||||
"error": undefined,
|
||||
"name": "Skipped test",
|
||||
"result": "skipped",
|
||||
"time": undefined,
|
||||
},
|
||||
TestCaseResult {
|
||||
"error": Object {
|
||||
"details": "Error: Timeout of 1ms exceeded. For async tests and hooks, ensure \\"done()\\" is called; if returning a Promise, ensure it resolves. (C:\\\\Users\\\\Michal\\\\Workspace\\\\dorny\\\\test-reporter\\\\reports\\\\mocha\\\\test\\\\second.test.js)
|
||||
at listOnTimeout (internal/timers.js:554:17)
|
||||
at processTimers (internal/timers.js:497:7)",
|
||||
"line": undefined,
|
||||
"message": "Timeout of 1ms exceeded. For async tests and hooks, ensure \\"done()\\" is called; if returning a Promise, ensure it resolves. (C:\\\\Users\\\\Michal\\\\Workspace\\\\dorny\\\\test-reporter\\\\reports\\\\mocha\\\\test\\\\second.test.js)",
|
||||
"path": undefined,
|
||||
},
|
||||
"name": "Timeout test",
|
||||
"result": "failed",
|
||||
"time": 10,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
"name": "test/second.test.js",
|
||||
"totalTime": undefined,
|
||||
},
|
||||
TestSuiteResult {
|
||||
"groups": Array [
|
||||
TestGroupResult {
|
||||
"name": "Array #indexOf()",
|
||||
"tests": Array [
|
||||
TestCaseResult {
|
||||
"error": Object {
|
||||
"details": "AssertionError [ERR_ASSERTION]: 2 == -1
|
||||
at Context.<anonymous> (test\\\\test.js:5:14)
|
||||
at processImmediate (internal/timers.js:461:21)",
|
||||
"line": undefined,
|
||||
"message": "2 == -1",
|
||||
"path": undefined,
|
||||
},
|
||||
"name": "should return -1 when the value is not present",
|
||||
"result": "failed",
|
||||
"time": 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
"name": "test/test.js",
|
||||
"totalTime": undefined,
|
||||
},
|
||||
],
|
||||
"totalTime": 14,
|
||||
}
|
||||
`;
|
||||
192
__tests__/fixtures/mocha-json.json
Normal file
192
__tests__/fixtures/mocha-json.json
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
{
|
||||
"stats": {
|
||||
"suites": 5,
|
||||
"tests": 7,
|
||||
"passes": 1,
|
||||
"pending": 1,
|
||||
"failures": 5,
|
||||
"start": "2021-02-23T14:20:41.144Z",
|
||||
"end": "2021-02-23T14:20:41.158Z",
|
||||
"duration": 14
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"title": "Timeout test",
|
||||
"fullTitle": "Timeout test",
|
||||
"file": "C:\\Users\\Michal\\Workspace\\dorny\\test-reporter\\reports\\mocha\\test\\second.test.js",
|
||||
"duration": 10,
|
||||
"currentRetry": 0,
|
||||
"err": {
|
||||
"stack": "Error: Timeout of 1ms exceeded. For async tests and hooks, ensure \"done()\" is called; if returning a Promise, ensure it resolves. (C:\\Users\\Michal\\Workspace\\dorny\\test-reporter\\reports\\mocha\\test\\second.test.js)\n at listOnTimeout (internal/timers.js:554:17)\n at processTimers (internal/timers.js:497:7)",
|
||||
"message": "Timeout of 1ms exceeded. For async tests and hooks, ensure \"done()\" is called; if returning a Promise, ensure it resolves. (C:\\Users\\Michal\\Workspace\\dorny\\test-reporter\\reports\\mocha\\test\\second.test.js)",
|
||||
"code": "ERR_MOCHA_TIMEOUT",
|
||||
"timeout": 1,
|
||||
"file": "C:\\Users\\Michal\\Workspace\\dorny\\test-reporter\\reports\\mocha\\test\\second.test.js"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Skipped test",
|
||||
"fullTitle": "Skipped test",
|
||||
"file": "C:\\Users\\Michal\\Workspace\\dorny\\test-reporter\\reports\\mocha\\test\\second.test.js",
|
||||
"currentRetry": 0,
|
||||
"err": {}
|
||||
},
|
||||
{
|
||||
"title": "Passing test",
|
||||
"fullTitle": "Test 1 Passing test",
|
||||
"file": "C:\\Users\\Michal\\Workspace\\dorny\\test-reporter\\reports\\mocha\\test\\main.test.js",
|
||||
"duration": 0,
|
||||
"currentRetry": 0,
|
||||
"speed": "fast",
|
||||
"err": {}
|
||||
},
|
||||
{
|
||||
"title": "Failing test",
|
||||
"fullTitle": "Test 1 Test 1.1 Failing test",
|
||||
"file": "C:\\Users\\Michal\\Workspace\\dorny\\test-reporter\\reports\\mocha\\test\\main.test.js",
|
||||
"duration": 1,
|
||||
"currentRetry": 0,
|
||||
"err": {
|
||||
"stack": "AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:\n\nfalse !== true\n\n at Context.<anonymous> (test\\main.test.js:11:14)\n at processImmediate (internal/timers.js:461:21)",
|
||||
"message": "Expected values to be strictly equal:\n\nfalse !== true\n",
|
||||
"generatedMessage": true,
|
||||
"name": "AssertionError",
|
||||
"code": "ERR_ASSERTION",
|
||||
"actual": "false",
|
||||
"expected": "true",
|
||||
"operator": "strictEqual"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Exception in target unit",
|
||||
"fullTitle": "Test 1 Test 1.1 Exception in target unit",
|
||||
"file": "C:\\Users\\Michal\\Workspace\\dorny\\test-reporter\\reports\\mocha\\test\\main.test.js",
|
||||
"duration": 0,
|
||||
"currentRetry": 0,
|
||||
"err": {
|
||||
"stack": "Error: Some error\n at Object.throwError (lib\\main.js:2:9)\n at Context.<anonymous> (test\\main.test.js:15:11)\n at processImmediate (internal/timers.js:461:21)",
|
||||
"message": "Some error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Exception in test",
|
||||
"fullTitle": "Test 2 Exception in test",
|
||||
"file": "C:\\Users\\Michal\\Workspace\\dorny\\test-reporter\\reports\\mocha\\test\\main.test.js",
|
||||
"duration": 0,
|
||||
"currentRetry": 0,
|
||||
"err": {
|
||||
"stack": "Error: Some error\n at Context.<anonymous> (test\\main.test.js:22:11)\n at processImmediate (internal/timers.js:461:21)",
|
||||
"message": "Some error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "should return -1 when the value is not present",
|
||||
"fullTitle": "Array #indexOf() should return -1 when the value is not present",
|
||||
"file": "C:\\Users\\Michal\\Workspace\\dorny\\test-reporter\\reports\\mocha\\test\\test.js",
|
||||
"duration": 0,
|
||||
"currentRetry": 0,
|
||||
"err": {
|
||||
"stack": "AssertionError [ERR_ASSERTION]: 2 == -1\n at Context.<anonymous> (test\\test.js:5:14)\n at processImmediate (internal/timers.js:461:21)",
|
||||
"message": "2 == -1",
|
||||
"generatedMessage": true,
|
||||
"name": "AssertionError",
|
||||
"code": "ERR_ASSERTION",
|
||||
"actual": "2",
|
||||
"expected": "-1",
|
||||
"operator": "=="
|
||||
}
|
||||
}
|
||||
],
|
||||
"pending": [
|
||||
{
|
||||
"title": "Skipped test",
|
||||
"fullTitle": "Skipped test",
|
||||
"file": "C:\\Users\\Michal\\Workspace\\dorny\\test-reporter\\reports\\mocha\\test\\second.test.js",
|
||||
"currentRetry": 0,
|
||||
"err": {}
|
||||
}
|
||||
],
|
||||
"failures": [
|
||||
{
|
||||
"title": "Timeout test",
|
||||
"fullTitle": "Timeout test",
|
||||
"file": "C:\\Users\\Michal\\Workspace\\dorny\\test-reporter\\reports\\mocha\\test\\second.test.js",
|
||||
"duration": 10,
|
||||
"currentRetry": 0,
|
||||
"err": {
|
||||
"stack": "Error: Timeout of 1ms exceeded. For async tests and hooks, ensure \"done()\" is called; if returning a Promise, ensure it resolves. (C:\\Users\\Michal\\Workspace\\dorny\\test-reporter\\reports\\mocha\\test\\second.test.js)\n at listOnTimeout (internal/timers.js:554:17)\n at processTimers (internal/timers.js:497:7)",
|
||||
"message": "Timeout of 1ms exceeded. For async tests and hooks, ensure \"done()\" is called; if returning a Promise, ensure it resolves. (C:\\Users\\Michal\\Workspace\\dorny\\test-reporter\\reports\\mocha\\test\\second.test.js)",
|
||||
"code": "ERR_MOCHA_TIMEOUT",
|
||||
"timeout": 1,
|
||||
"file": "C:\\Users\\Michal\\Workspace\\dorny\\test-reporter\\reports\\mocha\\test\\second.test.js"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Failing test",
|
||||
"fullTitle": "Test 1 Test 1.1 Failing test",
|
||||
"file": "C:\\Users\\Michal\\Workspace\\dorny\\test-reporter\\reports\\mocha\\test\\main.test.js",
|
||||
"duration": 1,
|
||||
"currentRetry": 0,
|
||||
"err": {
|
||||
"stack": "AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:\n\nfalse !== true\n\n at Context.<anonymous> (test\\main.test.js:11:14)\n at processImmediate (internal/timers.js:461:21)",
|
||||
"message": "Expected values to be strictly equal:\n\nfalse !== true\n",
|
||||
"generatedMessage": true,
|
||||
"name": "AssertionError",
|
||||
"code": "ERR_ASSERTION",
|
||||
"actual": "false",
|
||||
"expected": "true",
|
||||
"operator": "strictEqual"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Exception in target unit",
|
||||
"fullTitle": "Test 1 Test 1.1 Exception in target unit",
|
||||
"file": "C:\\Users\\Michal\\Workspace\\dorny\\test-reporter\\reports\\mocha\\test\\main.test.js",
|
||||
"duration": 0,
|
||||
"currentRetry": 0,
|
||||
"err": {
|
||||
"stack": "Error: Some error\n at Object.throwError (lib\\main.js:2:9)\n at Context.<anonymous> (test\\main.test.js:15:11)\n at processImmediate (internal/timers.js:461:21)",
|
||||
"message": "Some error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Exception in test",
|
||||
"fullTitle": "Test 2 Exception in test",
|
||||
"file": "C:\\Users\\Michal\\Workspace\\dorny\\test-reporter\\reports\\mocha\\test\\main.test.js",
|
||||
"duration": 0,
|
||||
"currentRetry": 0,
|
||||
"err": {
|
||||
"stack": "Error: Some error\n at Context.<anonymous> (test\\main.test.js:22:11)\n at processImmediate (internal/timers.js:461:21)",
|
||||
"message": "Some error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "should return -1 when the value is not present",
|
||||
"fullTitle": "Array #indexOf() should return -1 when the value is not present",
|
||||
"file": "C:\\Users\\Michal\\Workspace\\dorny\\test-reporter\\reports\\mocha\\test\\test.js",
|
||||
"duration": 0,
|
||||
"currentRetry": 0,
|
||||
"err": {
|
||||
"stack": "AssertionError [ERR_ASSERTION]: 2 == -1\n at Context.<anonymous> (test\\test.js:5:14)\n at processImmediate (internal/timers.js:461:21)",
|
||||
"message": "2 == -1",
|
||||
"generatedMessage": true,
|
||||
"name": "AssertionError",
|
||||
"code": "ERR_ASSERTION",
|
||||
"actual": "2",
|
||||
"expected": "-1",
|
||||
"operator": "=="
|
||||
}
|
||||
}
|
||||
],
|
||||
"passes": [
|
||||
{
|
||||
"title": "Passing test",
|
||||
"fullTitle": "Test 1 Passing test",
|
||||
"file": "C:\\Users\\Michal\\Workspace\\dorny\\test-reporter\\reports\\mocha\\test\\main.test.js",
|
||||
"duration": 0,
|
||||
"currentRetry": 0,
|
||||
"speed": "fast",
|
||||
"err": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
29
__tests__/mocha-json.test.ts
Normal file
29
__tests__/mocha-json.test.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
|
||||
import {MochaJsonParser} from '../src/parsers/mocha-json/mocha-json-parser'
|
||||
import {ParseOptions} from '../src/test-parser'
|
||||
import {getReport} from '../src/report/get-report'
|
||||
import {normalizeFilePath} from '../src/utils/path-utils'
|
||||
|
||||
describe('mocha-json tests', () => {
|
||||
it('report from ./reports/mocha-json test results matches snapshot', async () => {
|
||||
const fixturePath = path.join(__dirname, 'fixtures', 'mocha-json.json')
|
||||
const outputPath = path.join(__dirname, '__outputs__', 'mocha-json.md')
|
||||
const filePath = normalizeFilePath(path.relative(__dirname, fixturePath))
|
||||
const fileContent = fs.readFileSync(fixturePath, {encoding: 'utf8'})
|
||||
|
||||
const opts: ParseOptions = {
|
||||
parseErrors: true,
|
||||
trackedFiles: ['test/main.test.js', 'test/second.test.js', 'lib/main.js']
|
||||
}
|
||||
|
||||
const parser = new MochaJsonParser(opts)
|
||||
const result = await parser.parse(filePath, fileContent)
|
||||
expect(result).toMatchSnapshot()
|
||||
|
||||
const report = getReport([result])
|
||||
fs.mkdirSync(path.dirname(outputPath), {recursive: true})
|
||||
fs.writeFileSync(outputPath, report)
|
||||
})
|
||||
})
|
||||
|
|
@ -22,6 +22,7 @@ inputs:
|
|||
- dotnet-trx
|
||||
- flutter-json
|
||||
- jest-junit
|
||||
- mocha-json
|
||||
required: true
|
||||
list-suites:
|
||||
description: |
|
||||
|
|
|
|||
194
dist/index.js
generated
vendored
194
dist/index.js
generated
vendored
|
|
@ -220,6 +220,7 @@ const get_report_1 = __nccwpck_require__(3737);
|
|||
const dart_json_parser_1 = __nccwpck_require__(4528);
|
||||
const dotnet_trx_parser_1 = __nccwpck_require__(2664);
|
||||
const jest_junit_parser_1 = __nccwpck_require__(1113);
|
||||
const mocha_json_parser_1 = __nccwpck_require__(6043);
|
||||
const path_utils_1 = __nccwpck_require__(4070);
|
||||
const github_utils_1 = __nccwpck_require__(3522);
|
||||
const markdown_utils_1 = __nccwpck_require__(6482);
|
||||
|
|
@ -359,6 +360,8 @@ class TestReporter {
|
|||
return new dart_json_parser_1.DartJsonParser(options, 'flutter');
|
||||
case 'jest-junit':
|
||||
return new jest_junit_parser_1.JestJunitParser(options);
|
||||
case 'mocha-json':
|
||||
return new mocha_json_parser_1.MochaJsonParser(options);
|
||||
default:
|
||||
throw new Error(`Input variable 'reporter' is set to invalid value '${reporter}'`);
|
||||
}
|
||||
|
|
@ -657,6 +660,7 @@ class DotnetTrxParser {
|
|||
const trx = await this.getTrxReport(path, content);
|
||||
const tc = this.getTestClasses(trx);
|
||||
const tr = this.getTestRunResult(path, trx, tc);
|
||||
tr.sort(true);
|
||||
return tr;
|
||||
}
|
||||
async getTrxReport(path, content) {
|
||||
|
|
@ -693,10 +697,6 @@ class DotnetTrxParser {
|
|||
tc.tests.push(test);
|
||||
}
|
||||
const result = Object.values(testClasses);
|
||||
result.sort((a, b) => a.name.localeCompare(b.name));
|
||||
for (const tc of result) {
|
||||
tc.tests.sort((a, b) => a.name.localeCompare(b.name));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
getTestRunResult(path, trx, testClasses) {
|
||||
|
|
@ -770,6 +770,7 @@ exports.DotnetTrxParser = DotnetTrxParser;
|
|||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.JestJunitParser = void 0;
|
||||
const xml2js_1 = __nccwpck_require__(6189);
|
||||
const node_utils_1 = __nccwpck_require__(5824);
|
||||
const path_utils_1 = __nccwpck_require__(4070);
|
||||
const test_results_1 = __nccwpck_require__(2768);
|
||||
class JestJunitParser {
|
||||
|
|
@ -833,7 +834,7 @@ class JestJunitParser {
|
|||
const details = tc.failure[0];
|
||||
let path;
|
||||
let line;
|
||||
const src = this.exceptionThrowSource(details);
|
||||
const src = node_utils_1.getExceptionSource(details, this.options.trackedFiles, file => this.getRelativePath(file));
|
||||
if (src) {
|
||||
path = src.path;
|
||||
line = src.line;
|
||||
|
|
@ -844,29 +845,13 @@ class JestJunitParser {
|
|||
details
|
||||
};
|
||||
}
|
||||
exceptionThrowSource(stackTrace) {
|
||||
const lines = stackTrace.split(/\r?\n/);
|
||||
const re = /\((.*):(\d+):\d+\)$/;
|
||||
const { trackedFiles } = this.options;
|
||||
for (const str of lines) {
|
||||
const match = str.match(re);
|
||||
if (match !== null) {
|
||||
const [_, fileStr, lineStr] = match;
|
||||
const filePath = path_utils_1.normalizeFilePath(fileStr);
|
||||
if (filePath.startsWith('internal/') || filePath.includes('/node_modules/')) {
|
||||
continue;
|
||||
}
|
||||
const workDir = this.getWorkDir(filePath);
|
||||
if (!workDir) {
|
||||
continue;
|
||||
}
|
||||
const path = filePath.substr(workDir.length);
|
||||
if (trackedFiles.includes(path)) {
|
||||
const line = parseInt(lineStr);
|
||||
return { path, line };
|
||||
}
|
||||
}
|
||||
getRelativePath(path) {
|
||||
path = path_utils_1.normalizeFilePath(path);
|
||||
const workDir = this.getWorkDir(path);
|
||||
if (workDir !== undefined && path.startsWith(workDir)) {
|
||||
path = path.substr(workDir.length);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
getWorkDir(path) {
|
||||
var _a, _b;
|
||||
|
|
@ -876,6 +861,107 @@ class JestJunitParser {
|
|||
exports.JestJunitParser = JestJunitParser;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 6043:
|
||||
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
||||
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.MochaJsonParser = void 0;
|
||||
const test_results_1 = __nccwpck_require__(2768);
|
||||
const node_utils_1 = __nccwpck_require__(5824);
|
||||
const path_utils_1 = __nccwpck_require__(4070);
|
||||
class MochaJsonParser {
|
||||
constructor(options) {
|
||||
this.options = options;
|
||||
}
|
||||
async parse(path, content) {
|
||||
const mocha = this.getMochaJson(path, content);
|
||||
const result = this.getTestRunResult(path, mocha);
|
||||
result.sort(true);
|
||||
return Promise.resolve(result);
|
||||
}
|
||||
getMochaJson(path, content) {
|
||||
try {
|
||||
return JSON.parse(content);
|
||||
}
|
||||
catch (e) {
|
||||
throw new Error(`Invalid JSON at ${path}\n\n${e}`);
|
||||
}
|
||||
}
|
||||
getTestRunResult(resultsPath, mocha) {
|
||||
const suitesMap = {};
|
||||
const getSuite = (test) => {
|
||||
var _a;
|
||||
const path = this.getRelativePath(test.file);
|
||||
return (_a = suitesMap[path]) !== null && _a !== void 0 ? _a : (suitesMap[path] = new test_results_1.TestSuiteResult(path, []));
|
||||
};
|
||||
for (const test of mocha.passes) {
|
||||
const suite = getSuite(test);
|
||||
this.processTest(suite, test, 'success');
|
||||
}
|
||||
for (const test of mocha.failures) {
|
||||
const suite = getSuite(test);
|
||||
this.processTest(suite, test, 'failed');
|
||||
}
|
||||
for (const test of mocha.pending) {
|
||||
const suite = getSuite(test);
|
||||
this.processTest(suite, test, 'skipped');
|
||||
}
|
||||
const suites = Object.values(suitesMap);
|
||||
return new test_results_1.TestRunResult(resultsPath, suites, mocha.stats.duration);
|
||||
}
|
||||
processTest(suite, test, result) {
|
||||
const groupName = test.fullTitle !== test.title
|
||||
? test.fullTitle.substr(0, test.fullTitle.length - test.title.length).trimEnd()
|
||||
: null;
|
||||
let group = suite.groups.find(grp => grp.name === groupName);
|
||||
if (group === undefined) {
|
||||
group = new test_results_1.TestGroupResult(groupName, []);
|
||||
suite.groups.push(group);
|
||||
}
|
||||
const error = this.getTestCaseError(test);
|
||||
const testCase = new test_results_1.TestCaseResult(test.title, result, test.duration, error);
|
||||
group.tests.push(testCase);
|
||||
}
|
||||
getTestCaseError(test) {
|
||||
const details = test.err.stack;
|
||||
const message = test.err.message;
|
||||
if (details === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
let path;
|
||||
let line;
|
||||
const src = node_utils_1.getExceptionSource(details, this.options.trackedFiles, file => this.getRelativePath(file));
|
||||
if (src) {
|
||||
path = src.path;
|
||||
line = src.line;
|
||||
}
|
||||
return {
|
||||
path,
|
||||
line,
|
||||
message,
|
||||
details
|
||||
};
|
||||
}
|
||||
getRelativePath(path) {
|
||||
path = path_utils_1.normalizeFilePath(path);
|
||||
const workDir = this.getWorkDir(path);
|
||||
if (workDir !== undefined && path.startsWith(workDir)) {
|
||||
path = path.substr(workDir.length);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
getWorkDir(path) {
|
||||
var _a, _b;
|
||||
return ((_b = (_a = this.options.workDir) !== null && _a !== void 0 ? _a : this.assumedWorkDir) !== null && _b !== void 0 ? _b : (this.assumedWorkDir = path_utils_1.getBasePath(path, this.options.trackedFiles)));
|
||||
}
|
||||
}
|
||||
exports.MochaJsonParser = MochaJsonParser;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 5867:
|
||||
|
|
@ -1228,6 +1314,14 @@ class TestRunResult {
|
|||
get failedSuites() {
|
||||
return this.suites.filter(s => s.result === 'failed');
|
||||
}
|
||||
sort(deep) {
|
||||
this.suites.sort((a, b) => a.name.localeCompare(b.name));
|
||||
if (deep) {
|
||||
for (const suite of this.suites) {
|
||||
suite.sort(deep);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.TestRunResult = TestRunResult;
|
||||
class TestSuiteResult {
|
||||
|
|
@ -1258,6 +1352,14 @@ class TestSuiteResult {
|
|||
get failedGroups() {
|
||||
return this.groups.filter(grp => grp.result === 'failed');
|
||||
}
|
||||
sort(deep) {
|
||||
this.groups.sort((a, b) => { var _a, _b; return ((_a = a.name) !== null && _a !== void 0 ? _a : '').localeCompare((_b = b.name) !== null && _b !== void 0 ? _b : ''); });
|
||||
if (deep) {
|
||||
for (const grp of this.groups) {
|
||||
grp.sort();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.TestSuiteResult = TestSuiteResult;
|
||||
class TestGroupResult {
|
||||
|
|
@ -1283,6 +1385,9 @@ class TestGroupResult {
|
|||
get failedTests() {
|
||||
return this.tests.filter(tc => tc.result === 'failed');
|
||||
}
|
||||
sort() {
|
||||
this.tests.sort((a, b) => a.name.localeCompare(b.name));
|
||||
}
|
||||
}
|
||||
exports.TestGroupResult = TestGroupResult;
|
||||
class TestCaseResult {
|
||||
|
|
@ -1566,6 +1671,41 @@ function formatTime(ms) {
|
|||
exports.formatTime = formatTime;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 5824:
|
||||
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
||||
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.getExceptionSource = void 0;
|
||||
const path_utils_1 = __nccwpck_require__(4070);
|
||||
function getExceptionSource(stackTrace, trackedFiles, getRelativePath) {
|
||||
const lines = stackTrace.split(/\r?\n/);
|
||||
const re = /\((.*):(\d+):\d+\)$/;
|
||||
for (const str of lines) {
|
||||
const match = str.match(re);
|
||||
if (match !== null) {
|
||||
const [_, fileStr, lineStr] = match;
|
||||
const filePath = path_utils_1.normalizeFilePath(fileStr);
|
||||
if (filePath.startsWith('internal/') || filePath.includes('/node_modules/')) {
|
||||
continue;
|
||||
}
|
||||
const path = getRelativePath(filePath);
|
||||
if (!path) {
|
||||
continue;
|
||||
}
|
||||
if (trackedFiles.includes(path)) {
|
||||
const line = parseInt(lineStr);
|
||||
return { path, line };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.getExceptionSource = getExceptionSource;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 7811:
|
||||
|
|
|
|||
2
dist/index.js.map
generated
vendored
2
dist/index.js.map
generated
vendored
File diff suppressed because one or more lines are too long
|
|
@ -14,7 +14,8 @@
|
|||
"all": "npm run build && npm run format && npm run lint && npm run package && npm test",
|
||||
"dart-fixture": "cd \"reports/dart\" && dart test --file-reporter=\"json:../../__tests__/fixtures/dart-json.json\"",
|
||||
"dotnet-fixture": "dotnet test reports/dotnet/DotnetTests.XUnitTests --logger \"trx;LogFileName=../../../../__tests__/fixtures/dotnet-trx.trx\"",
|
||||
"jest-fixture": "cd \"reports/jest\" && npm test"
|
||||
"jest-fixture": "cd \"reports/jest\" && npm test",
|
||||
"mocha-fixture": "cd \"reports/mocha\" && npm test"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
|
|||
5
reports/mocha/lib/main.js
Normal file
5
reports/mocha/lib/main.js
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
function throwError() {
|
||||
throw new Error('Some error')
|
||||
}
|
||||
|
||||
exports.throwError = throwError
|
||||
761
reports/mocha/package-lock.json
generated
Normal file
761
reports/mocha/package-lock.json
generated
Normal file
|
|
@ -0,0 +1,761 @@
|
|||
{
|
||||
"name": "mocha-fixture",
|
||||
"version": "0.0.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@ungap/promise-all-settled": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz",
|
||||
"integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==",
|
||||
"dev": true
|
||||
},
|
||||
"ansi-colors": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
|
||||
"integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
|
||||
"dev": true
|
||||
},
|
||||
"ansi-regex": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
|
||||
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
|
||||
"dev": true
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"anymatch": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
|
||||
"integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"normalize-path": "^3.0.0",
|
||||
"picomatch": "^2.0.4"
|
||||
}
|
||||
},
|
||||
"argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||
"dev": true
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
|
||||
"dev": true
|
||||
},
|
||||
"binary-extensions": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
|
||||
"dev": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"braces": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
||||
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fill-range": "^7.0.1"
|
||||
}
|
||||
},
|
||||
"browser-stdout": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
|
||||
"integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
|
||||
"dev": true
|
||||
},
|
||||
"camelcase": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz",
|
||||
"integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==",
|
||||
"dev": true
|
||||
},
|
||||
"chalk": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
|
||||
"integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^4.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"chokidar": {
|
||||
"version": "3.5.1",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz",
|
||||
"integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"anymatch": "~3.1.1",
|
||||
"braces": "~3.0.2",
|
||||
"fsevents": "~2.3.1",
|
||||
"glob-parent": "~5.1.0",
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
"normalize-path": "~3.0.0",
|
||||
"readdirp": "~3.5.0"
|
||||
}
|
||||
},
|
||||
"cliui": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
||||
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.0",
|
||||
"wrap-ansi": "^7.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-regex": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
|
||||
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
|
||||
"dev": true
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||
"dev": true
|
||||
},
|
||||
"string-width": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
|
||||
"integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
||||
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^5.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-name": "~1.1.4"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
||||
"dev": true
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
|
||||
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"decamelize": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
|
||||
"integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
|
||||
"dev": true
|
||||
},
|
||||
"diff": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
|
||||
"integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
|
||||
"dev": true
|
||||
},
|
||||
"emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"dev": true
|
||||
},
|
||||
"escalade": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
|
||||
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
|
||||
"dev": true
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
||||
"dev": true
|
||||
},
|
||||
"fill-range": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"find-up": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
|
||||
"integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"locate-path": "^6.0.0",
|
||||
"path-exists": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"flat": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
|
||||
"integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
|
||||
"dev": true
|
||||
},
|
||||
"fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
|
||||
"dev": true
|
||||
},
|
||||
"fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"get-caller-file": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||
"dev": true
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.1.6",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
|
||||
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.0.4",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"glob-parent": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
|
||||
"integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-glob": "^4.0.1"
|
||||
}
|
||||
},
|
||||
"growl": {
|
||||
"version": "1.10.5",
|
||||
"resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
|
||||
"integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==",
|
||||
"dev": true
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true
|
||||
},
|
||||
"he": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
||||
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
|
||||
"dev": true
|
||||
},
|
||||
"inflight": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"once": "^1.3.0",
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"dev": true
|
||||
},
|
||||
"is-binary-path": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"binary-extensions": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
|
||||
"dev": true
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
|
||||
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
|
||||
"dev": true
|
||||
},
|
||||
"is-glob": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
|
||||
"integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-extglob": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"is-number": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||
"dev": true
|
||||
},
|
||||
"is-plain-obj": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
|
||||
"integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
|
||||
"dev": true
|
||||
},
|
||||
"isexe": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
|
||||
"dev": true
|
||||
},
|
||||
"js-yaml": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz",
|
||||
"integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"argparse": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"locate-path": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
||||
"integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"p-locate": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"log-symbols": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz",
|
||||
"integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
},
|
||||
"mocha": {
|
||||
"version": "8.3.0",
|
||||
"resolved": "https://registry.npmjs.org/mocha/-/mocha-8.3.0.tgz",
|
||||
"integrity": "sha512-TQqyC89V1J/Vxx0DhJIXlq9gbbL9XFNdeLQ1+JsnZsVaSOV1z3tWfw0qZmQJGQRIfkvZcs7snQnZnOCKoldq1Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ungap/promise-all-settled": "1.1.2",
|
||||
"ansi-colors": "4.1.1",
|
||||
"browser-stdout": "1.3.1",
|
||||
"chokidar": "3.5.1",
|
||||
"debug": "4.3.1",
|
||||
"diff": "5.0.0",
|
||||
"escape-string-regexp": "4.0.0",
|
||||
"find-up": "5.0.0",
|
||||
"glob": "7.1.6",
|
||||
"growl": "1.10.5",
|
||||
"he": "1.2.0",
|
||||
"js-yaml": "4.0.0",
|
||||
"log-symbols": "4.0.0",
|
||||
"minimatch": "3.0.4",
|
||||
"ms": "2.1.3",
|
||||
"nanoid": "3.1.20",
|
||||
"serialize-javascript": "5.0.1",
|
||||
"strip-json-comments": "3.1.1",
|
||||
"supports-color": "8.1.1",
|
||||
"which": "2.0.2",
|
||||
"wide-align": "1.1.3",
|
||||
"workerpool": "6.1.0",
|
||||
"yargs": "16.2.0",
|
||||
"yargs-parser": "20.2.4",
|
||||
"yargs-unparser": "2.0.0"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"dev": true
|
||||
},
|
||||
"nanoid": {
|
||||
"version": "3.1.20",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz",
|
||||
"integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==",
|
||||
"dev": true
|
||||
},
|
||||
"normalize-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
|
||||
"dev": true
|
||||
},
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"p-limit": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
|
||||
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"yocto-queue": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"p-locate": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
|
||||
"integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"p-limit": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"path-exists": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
|
||||
"dev": true
|
||||
},
|
||||
"path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
|
||||
"dev": true
|
||||
},
|
||||
"picomatch": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
|
||||
"integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
|
||||
"dev": true
|
||||
},
|
||||
"randombytes": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.1.0"
|
||||
}
|
||||
},
|
||||
"readdirp": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
|
||||
"integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"picomatch": "^2.2.1"
|
||||
}
|
||||
},
|
||||
"require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
|
||||
"dev": true
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"dev": true
|
||||
},
|
||||
"serialize-javascript": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz",
|
||||
"integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"randombytes": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"string-width": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
|
||||
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-fullwidth-code-point": "^2.0.0",
|
||||
"strip-ansi": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
|
||||
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"strip-json-comments": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
|
||||
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
|
||||
"dev": true
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "8.1.1",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
|
||||
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-number": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"isexe": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"wide-align": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
|
||||
"integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"string-width": "^1.0.2 || 2"
|
||||
}
|
||||
},
|
||||
"workerpool": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.0.tgz",
|
||||
"integrity": "sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg==",
|
||||
"dev": true
|
||||
},
|
||||
"wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-regex": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
|
||||
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
|
||||
"dev": true
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||
"dev": true
|
||||
},
|
||||
"string-width": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
|
||||
"integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
||||
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^5.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
||||
"dev": true
|
||||
},
|
||||
"y18n": {
|
||||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz",
|
||||
"integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==",
|
||||
"dev": true
|
||||
},
|
||||
"yargs": {
|
||||
"version": "16.2.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
|
||||
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cliui": "^7.0.2",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.0",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^20.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-regex": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
|
||||
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
|
||||
"dev": true
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||
"dev": true
|
||||
},
|
||||
"string-width": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
|
||||
"integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
||||
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^5.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"yargs-parser": {
|
||||
"version": "20.2.4",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
|
||||
"integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
|
||||
"dev": true
|
||||
},
|
||||
"yargs-unparser": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
|
||||
"integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"camelcase": "^6.0.0",
|
||||
"decamelize": "^4.0.0",
|
||||
"flat": "^5.0.2",
|
||||
"is-plain-obj": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"yocto-queue": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
}
|
||||
15
reports/mocha/package.json
Normal file
15
reports/mocha/package.json
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"name": "mocha-fixture",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"description": "Generates test fixtures for test-reporter action",
|
||||
"scripts": {
|
||||
"test-json": "mocha --reporter json > ../../__tests__/fixtures/mocha-json.json",
|
||||
"test": "mocha"
|
||||
},
|
||||
"author": "Michal Dorner <dorner.michal@gmail.com>",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"mocha": "^8.3.0"
|
||||
}
|
||||
}
|
||||
24
reports/mocha/test/main.test.js
Normal file
24
reports/mocha/test/main.test.js
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
const assert = require('assert').strict;
|
||||
const lib = require('../lib/main')
|
||||
|
||||
describe('Test 1', () => {
|
||||
it('Passing test', () => {
|
||||
assert.equal(true, true)
|
||||
});
|
||||
|
||||
describe('Test 1.1', () => {
|
||||
it('Failing test', () => {
|
||||
assert.equal(false, true)
|
||||
});
|
||||
|
||||
it('Exception in target unit', () => {
|
||||
lib.throwError();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test 2', () => {
|
||||
it('Exception in test', () => {
|
||||
throw new Error('Some error');
|
||||
});
|
||||
});
|
||||
8
reports/mocha/test/second.test.js
Normal file
8
reports/mocha/test/second.test.js
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
it('Timeout test', async function(done) {
|
||||
this.timeout(1);
|
||||
setTimeout(done, 1000);
|
||||
});
|
||||
|
||||
it.skip('Skipped test', () => {
|
||||
// do nothing
|
||||
});
|
||||
|
|
@ -13,6 +13,7 @@ import {getReport} from './report/get-report'
|
|||
import {DartJsonParser} from './parsers/dart-json/dart-json-parser'
|
||||
import {DotnetTrxParser} from './parsers/dotnet-trx/dotnet-trx-parser'
|
||||
import {JestJunitParser} from './parsers/jest-junit/jest-junit-parser'
|
||||
import {MochaJsonParser} from './parsers/mocha-json/mocha-json-parser'
|
||||
|
||||
import {normalizeDirPath} from './utils/path-utils'
|
||||
import {getCheckRunContext} from './utils/github-utils'
|
||||
|
|
@ -186,6 +187,8 @@ class TestReporter {
|
|||
return new DartJsonParser(options, 'flutter')
|
||||
case 'jest-junit':
|
||||
return new JestJunitParser(options)
|
||||
case 'mocha-json':
|
||||
return new MochaJsonParser(options)
|
||||
default:
|
||||
throw new Error(`Input variable 'reporter' is set to invalid value '${reporter}'`)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ export class DotnetTrxParser implements TestParser {
|
|||
const trx = await this.getTrxReport(path, content)
|
||||
const tc = this.getTestClasses(trx)
|
||||
const tr = this.getTestRunResult(path, trx, tc)
|
||||
tr.sort(true)
|
||||
return tr
|
||||
}
|
||||
|
||||
|
|
@ -88,11 +89,6 @@ export class DotnetTrxParser implements TestParser {
|
|||
}
|
||||
|
||||
const result = Object.values(testClasses)
|
||||
result.sort((a, b) => a.name.localeCompare(b.name))
|
||||
for (const tc of result) {
|
||||
tc.tests.sort((a, b) => a.name.localeCompare(b.name))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import {ParseOptions, TestParser} from '../../test-parser'
|
|||
import {parseStringPromise} from 'xml2js'
|
||||
|
||||
import {JunitReport, TestCase, TestSuite} from './jest-junit-types'
|
||||
import {getExceptionSource} from '../../utils/node-utils'
|
||||
import {getBasePath, normalizeFilePath} from '../../utils/path-utils'
|
||||
|
||||
import {
|
||||
|
|
@ -81,7 +82,7 @@ export class JestJunitParser implements TestParser {
|
|||
let path
|
||||
let line
|
||||
|
||||
const src = this.exceptionThrowSource(details)
|
||||
const src = getExceptionSource(details, this.options.trackedFiles, file => this.getRelativePath(file))
|
||||
if (src) {
|
||||
path = src.path
|
||||
line = src.line
|
||||
|
|
@ -94,31 +95,13 @@ export class JestJunitParser implements TestParser {
|
|||
}
|
||||
}
|
||||
|
||||
private exceptionThrowSource(stackTrace: string): {path: string; line: number} | undefined {
|
||||
const lines = stackTrace.split(/\r?\n/)
|
||||
const re = /\((.*):(\d+):\d+\)$/
|
||||
|
||||
const {trackedFiles} = this.options
|
||||
for (const str of lines) {
|
||||
const match = str.match(re)
|
||||
if (match !== null) {
|
||||
const [_, fileStr, lineStr] = match
|
||||
const filePath = normalizeFilePath(fileStr)
|
||||
if (filePath.startsWith('internal/') || filePath.includes('/node_modules/')) {
|
||||
continue
|
||||
}
|
||||
const workDir = this.getWorkDir(filePath)
|
||||
if (!workDir) {
|
||||
continue
|
||||
}
|
||||
const path = filePath.substr(workDir.length)
|
||||
if (trackedFiles.includes(path)) {
|
||||
const line = parseInt(lineStr)
|
||||
|
||||
return {path, line}
|
||||
}
|
||||
}
|
||||
private getRelativePath(path: string): string {
|
||||
path = normalizeFilePath(path)
|
||||
const workDir = this.getWorkDir(path)
|
||||
if (workDir !== undefined && path.startsWith(workDir)) {
|
||||
path = path.substr(workDir.length)
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
private getWorkDir(path: string): string | undefined {
|
||||
|
|
|
|||
118
src/parsers/mocha-json/mocha-json-parser.ts
Normal file
118
src/parsers/mocha-json/mocha-json-parser.ts
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
import {ParseOptions, TestParser} from '../../test-parser'
|
||||
import {
|
||||
TestCaseError,
|
||||
TestCaseResult,
|
||||
TestExecutionResult,
|
||||
TestGroupResult,
|
||||
TestRunResult,
|
||||
TestSuiteResult
|
||||
} from '../../test-results'
|
||||
import {getExceptionSource} from '../../utils/node-utils'
|
||||
import {getBasePath, normalizeFilePath} from '../../utils/path-utils'
|
||||
import {MochaJson, MochaJsonTest} from './mocha-json-types'
|
||||
|
||||
export class MochaJsonParser implements TestParser {
|
||||
assumedWorkDir: string | undefined
|
||||
|
||||
constructor(readonly options: ParseOptions) {}
|
||||
|
||||
async parse(path: string, content: string): Promise<TestRunResult> {
|
||||
const mocha = this.getMochaJson(path, content)
|
||||
const result = this.getTestRunResult(path, mocha)
|
||||
result.sort(true)
|
||||
return Promise.resolve(result)
|
||||
}
|
||||
|
||||
private getMochaJson(path: string, content: string): MochaJson {
|
||||
try {
|
||||
return JSON.parse(content)
|
||||
} catch (e) {
|
||||
throw new Error(`Invalid JSON at ${path}\n\n${e}`)
|
||||
}
|
||||
}
|
||||
|
||||
private getTestRunResult(resultsPath: string, mocha: MochaJson): TestRunResult {
|
||||
const suitesMap: {[path: string]: TestSuiteResult} = {}
|
||||
|
||||
const getSuite = (test: MochaJsonTest): TestSuiteResult => {
|
||||
const path = this.getRelativePath(test.file)
|
||||
return suitesMap[path] ?? (suitesMap[path] = new TestSuiteResult(path, []))
|
||||
}
|
||||
|
||||
for (const test of mocha.passes) {
|
||||
const suite = getSuite(test)
|
||||
this.processTest(suite, test, 'success')
|
||||
}
|
||||
|
||||
for (const test of mocha.failures) {
|
||||
const suite = getSuite(test)
|
||||
this.processTest(suite, test, 'failed')
|
||||
}
|
||||
|
||||
for (const test of mocha.pending) {
|
||||
const suite = getSuite(test)
|
||||
this.processTest(suite, test, 'skipped')
|
||||
}
|
||||
|
||||
const suites = Object.values(suitesMap)
|
||||
return new TestRunResult(resultsPath, suites, mocha.stats.duration)
|
||||
}
|
||||
|
||||
private processTest(suite: TestSuiteResult, test: MochaJsonTest, result: TestExecutionResult): void {
|
||||
const groupName =
|
||||
test.fullTitle !== test.title
|
||||
? test.fullTitle.substr(0, test.fullTitle.length - test.title.length).trimEnd()
|
||||
: null
|
||||
|
||||
let group = suite.groups.find(grp => grp.name === groupName)
|
||||
if (group === undefined) {
|
||||
group = new TestGroupResult(groupName, [])
|
||||
suite.groups.push(group)
|
||||
}
|
||||
|
||||
const error = this.getTestCaseError(test)
|
||||
const testCase = new TestCaseResult(test.title, result, test.duration, error)
|
||||
group.tests.push(testCase)
|
||||
}
|
||||
|
||||
private getTestCaseError(test: MochaJsonTest): TestCaseError | undefined {
|
||||
const details = test.err.stack
|
||||
const message = test.err.message
|
||||
if (details === undefined) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
let path
|
||||
let line
|
||||
|
||||
const src = getExceptionSource(details, this.options.trackedFiles, file => this.getRelativePath(file))
|
||||
if (src) {
|
||||
path = src.path
|
||||
line = src.line
|
||||
}
|
||||
|
||||
return {
|
||||
path,
|
||||
line,
|
||||
message,
|
||||
details
|
||||
}
|
||||
}
|
||||
|
||||
private getRelativePath(path: string): string {
|
||||
path = normalizeFilePath(path)
|
||||
const workDir = this.getWorkDir(path)
|
||||
if (workDir !== undefined && path.startsWith(workDir)) {
|
||||
path = path.substr(workDir.length)
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
private getWorkDir(path: string): string | undefined {
|
||||
return (
|
||||
this.options.workDir ??
|
||||
this.assumedWorkDir ??
|
||||
(this.assumedWorkDir = getBasePath(path, this.options.trackedFiles))
|
||||
)
|
||||
}
|
||||
}
|
||||
23
src/parsers/mocha-json/mocha-json-types.ts
Normal file
23
src/parsers/mocha-json/mocha-json-types.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
export interface MochaJson {
|
||||
stats: MochaJsonStats
|
||||
passes: MochaJsonTest[]
|
||||
pending: MochaJsonTest[]
|
||||
failures: MochaJsonTest[]
|
||||
}
|
||||
|
||||
export interface MochaJsonStats {
|
||||
duration: number
|
||||
}
|
||||
|
||||
export interface MochaJsonTest {
|
||||
title: string
|
||||
fullTitle: string
|
||||
file: string
|
||||
duration: number
|
||||
err: MochaJsonTestError
|
||||
}
|
||||
|
||||
export interface MochaJsonTestError {
|
||||
stack?: string
|
||||
message?: string
|
||||
}
|
||||
|
|
@ -26,6 +26,15 @@ export class TestRunResult {
|
|||
get failedSuites(): TestSuiteResult[] {
|
||||
return this.suites.filter(s => s.result === 'failed')
|
||||
}
|
||||
|
||||
sort(deep: boolean): void {
|
||||
this.suites.sort((a, b) => a.name.localeCompare(b.name))
|
||||
if (deep) {
|
||||
for (const suite of this.suites) {
|
||||
suite.sort(deep)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class TestSuiteResult {
|
||||
|
|
@ -55,6 +64,15 @@ export class TestSuiteResult {
|
|||
get failedGroups(): TestGroupResult[] {
|
||||
return this.groups.filter(grp => grp.result === 'failed')
|
||||
}
|
||||
|
||||
sort(deep: boolean): void {
|
||||
this.groups.sort((a, b) => (a.name ?? '').localeCompare(b.name ?? ''))
|
||||
if (deep) {
|
||||
for (const grp of this.groups) {
|
||||
grp.sort()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class TestGroupResult {
|
||||
|
|
@ -80,6 +98,10 @@ export class TestGroupResult {
|
|||
get failedTests(): TestCaseResult[] {
|
||||
return this.tests.filter(tc => tc.result === 'failed')
|
||||
}
|
||||
|
||||
sort(): void {
|
||||
this.tests.sort((a, b) => a.name.localeCompare(b.name))
|
||||
}
|
||||
}
|
||||
|
||||
export class TestCaseResult {
|
||||
|
|
|
|||
30
src/utils/node-utils.ts
Normal file
30
src/utils/node-utils.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import {normalizeFilePath} from './path-utils'
|
||||
|
||||
export function getExceptionSource(
|
||||
stackTrace: string,
|
||||
trackedFiles: string[],
|
||||
getRelativePath: (str: string) => string
|
||||
): {path: string; line: number} | undefined {
|
||||
const lines = stackTrace.split(/\r?\n/)
|
||||
const re = /\((.*):(\d+):\d+\)$/
|
||||
|
||||
for (const str of lines) {
|
||||
const match = str.match(re)
|
||||
if (match !== null) {
|
||||
const [_, fileStr, lineStr] = match
|
||||
const filePath = normalizeFilePath(fileStr)
|
||||
if (filePath.startsWith('internal/') || filePath.includes('/node_modules/')) {
|
||||
continue
|
||||
}
|
||||
const path = getRelativePath(filePath)
|
||||
if (!path) {
|
||||
continue
|
||||
}
|
||||
if (trackedFiles.includes(path)) {
|
||||
const line = parseInt(lineStr)
|
||||
|
||||
return {path, line}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue