@quenty/nevermore-cli 4.41.1 → 4.42.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/commands/batch-command/batch-test-command.d.ts.map +1 -1
- package/dist/commands/batch-command/batch-test-command.js +18 -2
- package/dist/commands/batch-command/batch-test-command.js.map +1 -1
- package/dist/commands/test-command/test-command.d.ts.map +1 -1
- package/dist/commands/test-command/test-command.js +6 -4
- package/dist/commands/test-command/test-command.js.map +1 -1
- package/dist/utils/open-cloud/open-cloud-client.d.ts.map +1 -1
- package/dist/utils/open-cloud/open-cloud-client.js +4 -1
- package/dist/utils/open-cloud/open-cloud-client.js.map +1 -1
- package/dist/utils/testing/parsers/batch-log-parser.d.ts +13 -5
- package/dist/utils/testing/parsers/batch-log-parser.d.ts.map +1 -1
- package/dist/utils/testing/parsers/batch-log-parser.js +114 -68
- package/dist/utils/testing/parsers/batch-log-parser.js.map +1 -1
- package/dist/utils/testing/parsers/batch-log-parser.test.js +57 -5
- package/dist/utils/testing/parsers/batch-log-parser.test.js.map +1 -1
- package/dist/utils/testing/parsers/traceback-parser.d.ts +31 -0
- package/dist/utils/testing/parsers/traceback-parser.d.ts.map +1 -0
- package/dist/utils/testing/parsers/traceback-parser.js +91 -0
- package/dist/utils/testing/parsers/traceback-parser.js.map +1 -0
- package/dist/utils/testing/parsers/traceback-parser.test.d.ts +2 -0
- package/dist/utils/testing/parsers/traceback-parser.test.d.ts.map +1 -0
- package/dist/utils/testing/parsers/traceback-parser.test.js +45 -0
- package/dist/utils/testing/parsers/traceback-parser.test.js.map +1 -0
- package/dist/utils/testing/runner/test-runner.d.ts +8 -0
- package/dist/utils/testing/runner/test-runner.d.ts.map +1 -1
- package/dist/utils/testing/runner/test-runner.js +28 -3
- package/dist/utils/testing/runner/test-runner.js.map +1 -1
- package/dist/utils/testing/runner/test-runner.test.d.ts +2 -0
- package/dist/utils/testing/runner/test-runner.test.d.ts.map +1 -0
- package/dist/utils/testing/runner/test-runner.test.js +18 -0
- package/dist/utils/testing/runner/test-runner.test.js.map +1 -0
- package/dist/utils/testing/test-log-parser.d.ts +32 -1
- package/dist/utils/testing/test-log-parser.d.ts.map +1 -1
- package/dist/utils/testing/test-log-parser.js +53 -9
- package/dist/utils/testing/test-log-parser.js.map +1 -1
- package/dist/utils/testing/test-log-parser.test.d.ts +2 -0
- package/dist/utils/testing/test-log-parser.test.d.ts.map +1 -0
- package/dist/utils/testing/test-log-parser.test.js +56 -0
- package/dist/utils/testing/test-log-parser.test.js.map +1 -0
- package/package.json +2 -2
- package/src/commands/batch-command/batch-test-command.ts +78 -58
- package/src/commands/test-command/test-command.ts +7 -4
- package/src/utils/open-cloud/open-cloud-client.ts +4 -1
- package/src/utils/testing/parsers/batch-log-parser.test.ts +70 -5
- package/src/utils/testing/parsers/batch-log-parser.ts +141 -80
- package/src/utils/testing/parsers/traceback-parser.test.ts +64 -0
- package/src/utils/testing/parsers/traceback-parser.ts +122 -0
- package/src/utils/testing/runner/test-runner.test.ts +29 -0
- package/src/utils/testing/runner/test-runner.ts +35 -3
- package/src/utils/testing/test-log-parser.test.ts +70 -0
- package/src/utils/testing/test-log-parser.ts +80 -10
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { countTracebacks, parseBatchTestLogs } from './batch-log-parser.js';
|
|
2
|
+
import { countTracebacks, findSummaryEntries, parseBatchTestLogs, } from './batch-log-parser.js';
|
|
3
3
|
const SLUG_MAP = new Map([['egghunt2026', 'egghunt2026']]);
|
|
4
4
|
function buildLogs(section) {
|
|
5
5
|
return [
|
|
@@ -16,18 +16,53 @@ describe('parseBatchTestLogs', () => {
|
|
|
16
16
|
const result = parseBatchTestLogs(logs, SLUG_MAP).get('egghunt2026');
|
|
17
17
|
expect(result?.testCounts).toEqual({ passed: 275, failed: 0, total: 275 });
|
|
18
18
|
});
|
|
19
|
-
it('
|
|
20
|
-
//
|
|
21
|
-
//
|
|
19
|
+
it('attributes a section closed by END when its BEGIN was dropped', () => {
|
|
20
|
+
// Open Cloud keeps only the tail of a long run's log, so BEGIN — printed
|
|
21
|
+
// first — is the first casualty while END and the summary survive.
|
|
22
22
|
const logs = [
|
|
23
|
+
' ✓ some test that survived (3 ms)',
|
|
23
24
|
'Tests: 275 passed, 275 total',
|
|
24
25
|
'===BATCH_TEST_END egghunt2026 PASS 1000===',
|
|
25
26
|
'===BATCH_TEST_SUMMARY===',
|
|
26
27
|
'[{"slug":"egghunt2026","success":true,"durationMs":1000}]',
|
|
27
28
|
].join('\n');
|
|
28
29
|
const result = parseBatchTestLogs(logs, SLUG_MAP).get('egghunt2026');
|
|
30
|
+
expect(result?.success).toBe(true);
|
|
31
|
+
expect(result?.testCounts).toEqual({ passed: 275, failed: 0, total: 275 });
|
|
32
|
+
});
|
|
33
|
+
it('does not let an out-of-order END steal another package’s output', () => {
|
|
34
|
+
// The API does not deliver messages in order, so a stray END can arrive
|
|
35
|
+
// mid-section. Only the first section can have lost its head; past that the
|
|
36
|
+
// log is well-formed and a BEGIN-less END must not claim anything.
|
|
37
|
+
const twoPackages = new Map([
|
|
38
|
+
['alpha', 'alpha'],
|
|
39
|
+
['beta', 'beta'],
|
|
40
|
+
]);
|
|
41
|
+
const logs = [
|
|
42
|
+
'===BATCH_TEST_BEGIN alpha===',
|
|
43
|
+
'Tests: 10 passed, 10 total',
|
|
44
|
+
'===BATCH_TEST_END beta PASS 5===',
|
|
45
|
+
'===BATCH_TEST_END alpha PASS 10===',
|
|
46
|
+
'===BATCH_TEST_SUMMARY===',
|
|
47
|
+
'[{"slug":"alpha","success":true},{"slug":"beta","success":true}]',
|
|
48
|
+
].join('\n');
|
|
49
|
+
const results = parseBatchTestLogs(logs, twoPackages);
|
|
50
|
+
expect(results.get('alpha')?.testCounts?.total).toBe(10);
|
|
51
|
+
// beta never had a section of its own; it must not inherit alpha's.
|
|
52
|
+
expect(results.get('beta')?.testCounts).toBeUndefined();
|
|
53
|
+
expect(results.get('beta')?.success).toBe(false);
|
|
54
|
+
});
|
|
55
|
+
it('fails a pass it cannot read, rather than trusting the pcall', () => {
|
|
56
|
+
// No END marker either, so there is no boundary to attribute output with.
|
|
57
|
+
// The pcall said success, but nothing here saw a test run.
|
|
58
|
+
const logs = [
|
|
59
|
+
'Tests: 275 passed, 275 total',
|
|
60
|
+
'===BATCH_TEST_SUMMARY===',
|
|
61
|
+
'[{"slug":"egghunt2026","success":true,"durationMs":1000}]',
|
|
62
|
+
].join('\n');
|
|
63
|
+
const result = parseBatchTestLogs(logs, SLUG_MAP).get('egghunt2026');
|
|
29
64
|
expect(result?.success).toBe(false);
|
|
30
|
-
expect(result?.error).toContain('
|
|
65
|
+
expect(result?.error).toContain('no output could be attributed');
|
|
31
66
|
expect(result?.testCounts).toBeUndefined();
|
|
32
67
|
});
|
|
33
68
|
it('still shows output it could not attribute', () => {
|
|
@@ -54,6 +89,23 @@ describe('parseBatchTestLogs', () => {
|
|
|
54
89
|
expect(result?.tracebackCount).toBe(1);
|
|
55
90
|
});
|
|
56
91
|
});
|
|
92
|
+
describe('findSummaryEntries', () => {
|
|
93
|
+
it('finds the summary even when output landed after it', () => {
|
|
94
|
+
// Messages are not delivered in order, so a stray line can follow the
|
|
95
|
+
// summary. Treating the whole remainder as one JSON blob made the same
|
|
96
|
+
// batch parse on one run and fail on the next.
|
|
97
|
+
const lines = [
|
|
98
|
+
'[{"slug":"alpha","success":true}]',
|
|
99
|
+
' ✓ a stray line that arrived late',
|
|
100
|
+
];
|
|
101
|
+
expect(findSummaryEntries(lines, 0)).toEqual([
|
|
102
|
+
{ slug: 'alpha', success: true },
|
|
103
|
+
]);
|
|
104
|
+
});
|
|
105
|
+
it('returns undefined when there is no array to find', () => {
|
|
106
|
+
expect(findSummaryEntries(['not json at all'], 0)).toBeUndefined();
|
|
107
|
+
});
|
|
108
|
+
});
|
|
57
109
|
describe('countTracebacks', () => {
|
|
58
110
|
it('counts each traceback separately', () => {
|
|
59
111
|
expect(countTracebacks('Stack Begin\nfoo\nStack End\nStack Begin\n')).toBe(2);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"batch-log-parser.test.js","sourceRoot":"","sources":["../../../../src/utils/testing/parsers/batch-log-parser.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,
|
|
1
|
+
{"version":3,"file":"batch-log-parser.test.js","sourceRoot":"","sources":["../../../../src/utils/testing/parsers/batch-log-parser.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface AttributedTraceback {
|
|
2
|
+
/** First line of the error, before the stack. */
|
|
3
|
+
message: string;
|
|
4
|
+
/** Roblox instance path of the topmost frame, e.g. "ServerScriptService.Foo.Bar". */
|
|
5
|
+
source?: string;
|
|
6
|
+
/** Root of that path, which names the package the frame belongs to. */
|
|
7
|
+
owner?: string;
|
|
8
|
+
/** Frames kept for display, topmost first. */
|
|
9
|
+
frames: string[];
|
|
10
|
+
/** How many times this same traceback appeared. */
|
|
11
|
+
count: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Pull tracebacks out of log output and attribute each to its owning package.
|
|
15
|
+
*
|
|
16
|
+
* Attribution reads the script path in the frames rather than the position of
|
|
17
|
+
* the traceback in the log. Position is unreliable: a deferred callback can
|
|
18
|
+
* fire during a later package's section, which is why batch mode previously
|
|
19
|
+
* gave up on tracebacks entirely.
|
|
20
|
+
*/
|
|
21
|
+
export declare function parseTracebacks(rawOutput: string): AttributedTraceback[];
|
|
22
|
+
/**
|
|
23
|
+
* Name the package a script path belongs to.
|
|
24
|
+
*
|
|
25
|
+
* Batch places hold each package under its own root, so the segment below the
|
|
26
|
+
* service is the package.
|
|
27
|
+
*/
|
|
28
|
+
export declare function ownerOf(scriptPath: string): string | undefined;
|
|
29
|
+
/** Render tracebacks for a human, newest information first and bounded. */
|
|
30
|
+
export declare function formatTracebacks(tracebacks: AttributedTraceback[], maxShown?: number): string;
|
|
31
|
+
//# sourceMappingURL=traceback-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"traceback-parser.d.ts","sourceRoot":"","sources":["../../../../src/utils/testing/parsers/traceback-parser.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,mBAAmB;IAClC,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAC;IAChB,qFAAqF;IACrF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAC;CACf;AASD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,mBAAmB,EAAE,CAmDxE;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG9D;AAED,2EAA2E;AAC3E,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,mBAAmB,EAAE,EACjC,QAAQ,SAAI,GACX,MAAM,CAuBR"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { OutputHelper } from '@quenty/cli-output-helpers';
|
|
2
|
+
const STACK_BEGIN = /^\s*Stack Begin\s*$/;
|
|
3
|
+
const STACK_END = /^\s*Stack End\s*$/;
|
|
4
|
+
// Script 'ServerScriptService.EggHunt2026.game.Server.Foo', Line 365 - function bar
|
|
5
|
+
const FRAME = /Script\s+'(?:\[string\s+")?([^'"\]]+)/;
|
|
6
|
+
const MAX_FRAMES = 4;
|
|
7
|
+
/**
|
|
8
|
+
* Pull tracebacks out of log output and attribute each to its owning package.
|
|
9
|
+
*
|
|
10
|
+
* Attribution reads the script path in the frames rather than the position of
|
|
11
|
+
* the traceback in the log. Position is unreliable: a deferred callback can
|
|
12
|
+
* fire during a later package's section, which is why batch mode previously
|
|
13
|
+
* gave up on tracebacks entirely.
|
|
14
|
+
*/
|
|
15
|
+
export function parseTracebacks(rawOutput) {
|
|
16
|
+
if (!rawOutput) {
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
const lines = OutputHelper.stripAnsi(rawOutput).split('\n');
|
|
20
|
+
const bySignature = new Map();
|
|
21
|
+
for (let i = 0; i < lines.length; i++) {
|
|
22
|
+
if (!STACK_BEGIN.test(lines[i])) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
// The error text sits on the line above "Stack Begin".
|
|
26
|
+
const message = (lines[i - 1] ?? '').trim();
|
|
27
|
+
const frames = [];
|
|
28
|
+
let source;
|
|
29
|
+
for (let j = i + 1; j < lines.length && !STACK_END.test(lines[j]); j++) {
|
|
30
|
+
const frame = lines[j].trim();
|
|
31
|
+
if (!frame) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (frames.length < MAX_FRAMES) {
|
|
35
|
+
frames.push(frame);
|
|
36
|
+
}
|
|
37
|
+
if (!source) {
|
|
38
|
+
source = FRAME.exec(frame)?.[1];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// One bug fires per player and per frame, so the same traceback can appear
|
|
42
|
+
// hundreds of times. Collapse by signature and count instead of printing
|
|
43
|
+
// every copy.
|
|
44
|
+
const signature = `${message}::${frames[0] ?? ''}`;
|
|
45
|
+
const existing = bySignature.get(signature);
|
|
46
|
+
if (existing) {
|
|
47
|
+
existing.count++;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
bySignature.set(signature, {
|
|
51
|
+
message,
|
|
52
|
+
source,
|
|
53
|
+
owner: source ? ownerOf(source) : undefined,
|
|
54
|
+
frames,
|
|
55
|
+
count: 1,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return [...bySignature.values()];
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Name the package a script path belongs to.
|
|
62
|
+
*
|
|
63
|
+
* Batch places hold each package under its own root, so the segment below the
|
|
64
|
+
* service is the package.
|
|
65
|
+
*/
|
|
66
|
+
export function ownerOf(scriptPath) {
|
|
67
|
+
const parts = scriptPath.split('.');
|
|
68
|
+
return parts.length >= 2 ? parts[1] : undefined;
|
|
69
|
+
}
|
|
70
|
+
/** Render tracebacks for a human, newest information first and bounded. */
|
|
71
|
+
export function formatTracebacks(tracebacks, maxShown = 5) {
|
|
72
|
+
if (tracebacks.length === 0) {
|
|
73
|
+
return '';
|
|
74
|
+
}
|
|
75
|
+
const lines = [];
|
|
76
|
+
const shown = tracebacks.slice(0, maxShown);
|
|
77
|
+
for (const traceback of shown) {
|
|
78
|
+
const where = traceback.source ? ` (${traceback.source})` : '';
|
|
79
|
+
const times = traceback.count > 1 ? ` ×${traceback.count}` : '';
|
|
80
|
+
lines.push(` ${traceback.message}${where}${times}`);
|
|
81
|
+
for (const frame of traceback.frames) {
|
|
82
|
+
lines.push(` ${frame}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const hidden = tracebacks.length - shown.length;
|
|
86
|
+
if (hidden > 0) {
|
|
87
|
+
lines.push(` ...and ${hidden} more distinct traceback(s)`);
|
|
88
|
+
}
|
|
89
|
+
return lines.join('\n');
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=traceback-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"traceback-parser.js","sourceRoot":"","sources":["../../../../src/utils/testing/parsers/traceback-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"traceback-parser.test.d.ts","sourceRoot":"","sources":["../../../../src/utils/testing/parsers/traceback-parser.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { formatTracebacks, ownerOf, parseTracebacks, } from './traceback-parser.js';
|
|
3
|
+
const TRACEBACK = [
|
|
4
|
+
'PlayerBadgeHelper: attempt to index nil with UserId',
|
|
5
|
+
'Stack Begin',
|
|
6
|
+
'Script \'[string "ServerScriptService.egghunt2026.game.Server.PlayerBadgeHelper"]\', Line 365 - function _awardBadge',
|
|
7
|
+
'Script \'[string "ServerScriptService.egghunt2026.game.Server.PlayerBadgeHelper"]\', Line 138',
|
|
8
|
+
'Stack End',
|
|
9
|
+
].join('\n');
|
|
10
|
+
describe('parseTracebacks', () => {
|
|
11
|
+
it('attributes a traceback to the package that owns the failing script', () => {
|
|
12
|
+
const [traceback] = parseTracebacks(TRACEBACK);
|
|
13
|
+
expect(traceback.owner).toBe('egghunt2026');
|
|
14
|
+
expect(traceback.source).toContain('PlayerBadgeHelper');
|
|
15
|
+
expect(traceback.message).toContain('attempt to index nil');
|
|
16
|
+
});
|
|
17
|
+
it('collapses repeats of the same crash into one entry with a count', () => {
|
|
18
|
+
// One bug fires per player per frame, so raw output can hold hundreds of
|
|
19
|
+
// identical copies. Printing them all is what makes logs unreadable.
|
|
20
|
+
const repeated = [TRACEBACK, TRACEBACK, TRACEBACK].join('\n');
|
|
21
|
+
const tracebacks = parseTracebacks(repeated);
|
|
22
|
+
expect(tracebacks).toHaveLength(1);
|
|
23
|
+
expect(tracebacks[0].count).toBe(3);
|
|
24
|
+
});
|
|
25
|
+
it('keeps distinct crashes apart', () => {
|
|
26
|
+
const other = TRACEBACK.replace('PlayerBadgeHelper', 'TrainHelper');
|
|
27
|
+
expect(parseTracebacks([TRACEBACK, other].join('\n'))).toHaveLength(2);
|
|
28
|
+
});
|
|
29
|
+
it('finds nothing in clean output', () => {
|
|
30
|
+
expect(parseTracebacks('Tests: 10 passed, 10 total')).toEqual([]);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
describe('ownerOf', () => {
|
|
34
|
+
it('names the package below the service', () => {
|
|
35
|
+
expect(ownerOf('ServerScriptService.brio.Foo.Bar')).toBe('brio');
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
describe('formatTracebacks', () => {
|
|
39
|
+
it('bounds how many it prints and says how many it withheld', () => {
|
|
40
|
+
const many = Array.from({ length: 8 }, (_, i) => TRACEBACK.replace('PlayerBadgeHelper:', `Helper${i}:`)).join('\n');
|
|
41
|
+
const formatted = formatTracebacks(parseTracebacks(many), 5);
|
|
42
|
+
expect(formatted).toContain('and 3 more distinct traceback(s)');
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
//# sourceMappingURL=traceback-parser.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"traceback-parser.test.js","sourceRoot":"","sources":["../../../../src/utils/testing/parsers/traceback-parser.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EACL,gBAAgB,EAChB,OAAO,EACP,eAAe,GAChB,MAAM,uBAAuB,CAAC;AAE/B,MAAM,SAAS,GAAG;IAChB,qDAAqD;IACrD,aAAa;IACb,sHAAsH;IACtH,+FAA+F;IAC/F,WAAW;CACZ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,oEAAoE,EAAE,GAAG,EAAE;QAC5E,MAAM,CAAC,SAAS,CAAC,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;QAE/C,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC5C,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;QACxD,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,sBAAsB,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;QACzE,yEAAyE;QACzE,qEAAqE;QACrE,MAAM,QAAQ,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAE9D,MAAM,UAAU,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;QAE7C,MAAM,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,mBAAmB,EAAE,aAAa,CAAC,CAAC;QAEpE,MAAM,CAAC,eAAe,CAAC,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,eAAe,CAAC,4BAA4B,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE;IACvB,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,CAAC,OAAO,CAAC,kCAAkC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAC9C,SAAS,CAAC,OAAO,CAAC,oBAAoB,EAAE,SAAS,CAAC,GAAG,CAAC,CACvD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEb,MAAM,SAAS,GAAG,gBAAgB,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QAE7D,MAAM,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,kCAAkC,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -14,6 +14,14 @@ export interface SingleTestResult {
|
|
|
14
14
|
/** Why the run failed, when the runner can say more than "it failed". */
|
|
15
15
|
error?: string;
|
|
16
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Combine failure reasons from the job context with those read from the logs.
|
|
19
|
+
*
|
|
20
|
+
* In batch mode the context has already evaluated these same logs, so the two
|
|
21
|
+
* sources overlap. Merging on the individual reason keeps the overlap from
|
|
22
|
+
* reading as double the failures.
|
|
23
|
+
*/
|
|
24
|
+
export declare function mergeFailureReasons(contextError: string | undefined, logReasons: string[]): string[];
|
|
17
25
|
export interface SingleTestOptions {
|
|
18
26
|
packagePath: string;
|
|
19
27
|
packageName: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-runner.d.ts","sourceRoot":"","sources":["../../../../src/utils/testing/runner/test-runner.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EACL,KAAK,gBAAgB,EAGtB,MAAM,uBAAuB,CAAC;AAS/B,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,MAAM,EAAE,YAAY,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,UAAU,EACnB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,gBAAgB,CAAC,
|
|
1
|
+
{"version":3,"file":"test-runner.d.ts","sourceRoot":"","sources":["../../../../src/utils/testing/runner/test-runner.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EACL,KAAK,gBAAgB,EAGtB,MAAM,uBAAuB,CAAC;AAS/B,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,UAAU,EAAE,MAAM,EAAE,GACnB,MAAM,EAAE,CAOV;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,MAAM,EAAE,YAAY,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,UAAU,EACnB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,gBAAgB,CAAC,CA6E3B;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,OAAO,CAAC,MAAM,CAAC,CAajB"}
|
|
@@ -4,6 +4,21 @@ import { randomUUID } from 'crypto';
|
|
|
4
4
|
import { parseTestLogs, parseTestCounts, } from '../test-log-parser.js';
|
|
5
5
|
import { buildDeployMetadataAttributes, gatherGitDeployInfo, injectDeployMetadataInPlaceAsync, packageUsesManifestAsync, } from '../../deploy/deploy-metadata.js';
|
|
6
6
|
import { readPackageVersionAsync } from '../../nevermore-cli-utils.js';
|
|
7
|
+
/**
|
|
8
|
+
* Combine failure reasons from the job context with those read from the logs.
|
|
9
|
+
*
|
|
10
|
+
* In batch mode the context has already evaluated these same logs, so the two
|
|
11
|
+
* sources overlap. Merging on the individual reason keeps the overlap from
|
|
12
|
+
* reading as double the failures.
|
|
13
|
+
*/
|
|
14
|
+
export function mergeFailureReasons(contextError, logReasons) {
|
|
15
|
+
return [
|
|
16
|
+
...new Set([
|
|
17
|
+
...(contextError ? contextError.split('; ') : []),
|
|
18
|
+
...logReasons,
|
|
19
|
+
]),
|
|
20
|
+
];
|
|
21
|
+
}
|
|
7
22
|
/**
|
|
8
23
|
* Build, deploy, and run a test for a single package using the provided
|
|
9
24
|
* JobContext. The context determines the execution environment (cloud or local).
|
|
@@ -11,7 +26,11 @@ import { readPackageVersionAsync } from '../../nevermore-cli-utils.js';
|
|
|
11
26
|
* Creates and releases its own deployment handle — the caller owns the context lifetime.
|
|
12
27
|
*/
|
|
13
28
|
export async function runSingleTestAsync(context, options) {
|
|
14
|
-
const { packagePath, packageName,
|
|
29
|
+
const { packagePath, packageName,
|
|
30
|
+
// 300s is the Open Cloud maximum. The old 120s default failed real suites
|
|
31
|
+
// with no jest summary at all, so "--timeout 300" had become folklore
|
|
32
|
+
// everyone had to know before their first useful run.
|
|
33
|
+
timeoutMs = 300_000, scriptText, target, } = options;
|
|
15
34
|
const sessionId = randomUUID();
|
|
16
35
|
const builtPlace = await context.buildPlaceAsync({
|
|
17
36
|
target,
|
|
@@ -46,13 +65,19 @@ export async function runSingleTestAsync(context, options) {
|
|
|
46
65
|
timeoutMs,
|
|
47
66
|
});
|
|
48
67
|
const rawLogs = await context.getLogsAsync(deployment);
|
|
49
|
-
|
|
68
|
+
// A probe script is arbitrary Luau with no jest in it, so demanding a test
|
|
69
|
+
// report would fail every --script-text run. Everything else must prove a
|
|
70
|
+
// runner spoke before it can pass.
|
|
71
|
+
const parsed = parseTestLogs(rawLogs, {
|
|
72
|
+
requireTestReport: scriptText === undefined,
|
|
73
|
+
});
|
|
74
|
+
const reasons = mergeFailureReasons(result.errorMessage, parsed.failureReasons);
|
|
50
75
|
return {
|
|
51
76
|
success: result.success && parsed.success,
|
|
52
77
|
logs: parsed.logs,
|
|
53
78
|
testCounts: parseTestCounts(parsed.logs),
|
|
54
79
|
durationMs: result.durationMs,
|
|
55
|
-
error:
|
|
80
|
+
error: reasons.length > 0 ? reasons.join('; ') : undefined,
|
|
56
81
|
};
|
|
57
82
|
}
|
|
58
83
|
finally {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-runner.js","sourceRoot":"","sources":["../../../../src/utils/testing/runner/test-runner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAGpC,OAAO,EAEL,aAAa,EACb,eAAe,GAChB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,6BAA6B,EAC7B,mBAAmB,EACnB,gCAAgC,EAChC,wBAAwB,GACzB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"test-runner.js","sourceRoot":"","sources":["../../../../src/utils/testing/runner/test-runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-runner.test.d.ts","sourceRoot":"","sources":["../../../../src/utils/testing/runner/test-runner.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { mergeFailureReasons } from './test-runner.js';
|
|
3
|
+
describe('mergeFailureReasons', () => {
|
|
4
|
+
it('does not repeat reasons the context already reported', () => {
|
|
5
|
+
// Batch mode evaluates the same logs upstream, so both sources describe the
|
|
6
|
+
// same failures. Concatenating them read as double the failures.
|
|
7
|
+
const merged = mergeFailureReasons('3 test suite(s) failed; 19 test(s) failed', ['3 test suite(s) failed', '19 test(s) failed']);
|
|
8
|
+
expect(merged).toEqual(['3 test suite(s) failed', '19 test(s) failed']);
|
|
9
|
+
});
|
|
10
|
+
it('keeps reasons only one side knows about', () => {
|
|
11
|
+
const merged = mergeFailureReasons('the batch runner reported a Luau error', ['19 test(s) failed']);
|
|
12
|
+
expect(merged).toHaveLength(2);
|
|
13
|
+
});
|
|
14
|
+
it('is empty when nothing failed', () => {
|
|
15
|
+
expect(mergeFailureReasons(undefined, [])).toEqual([]);
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
//# sourceMappingURL=test-runner.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-runner.test.js","sourceRoot":"","sources":["../../../../src/utils/testing/runner/test-runner.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,4EAA4E;QAC5E,iEAAiE;QACjE,MAAM,MAAM,GAAG,mBAAmB,CAChC,2CAA2C,EAC3C,CAAC,wBAAwB,EAAE,mBAAmB,CAAC,CAChD,CAAC;QAEF,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,wBAAwB,EAAE,mBAAmB,CAAC,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,MAAM,GAAG,mBAAmB,CAChC,wCAAwC,EACxC,CAAC,mBAAmB,CAAC,CACtB,CAAC;QAEF,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -7,12 +7,43 @@ export interface ParsedTestLogs {
|
|
|
7
7
|
success: boolean;
|
|
8
8
|
logs: string;
|
|
9
9
|
testCounts?: ParsedTestCounts;
|
|
10
|
+
/** Why the run is not a pass. Empty when it is. */
|
|
11
|
+
failureReasons: string[];
|
|
10
12
|
}
|
|
13
|
+
export interface TestOutcomeOptions {
|
|
14
|
+
/**
|
|
15
|
+
* Require proof the runner ran. Off for probe scripts (--script-text), which
|
|
16
|
+
* legitimately produce no jest report.
|
|
17
|
+
*/
|
|
18
|
+
requireTestReport?: boolean;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Decide whether test output represents a pass, and say why when it does not.
|
|
22
|
+
*
|
|
23
|
+
* The single definition of the rule. Both the single-package path and the batch
|
|
24
|
+
* path route through here — they previously carried divergent copies that
|
|
25
|
+
* disagreed about tracebacks, so the same commit could pass one and fail the
|
|
26
|
+
* other.
|
|
27
|
+
*/
|
|
28
|
+
export declare function evaluateTestOutcome(rawOutput: string, options?: TestOutcomeOptions): {
|
|
29
|
+
success: boolean;
|
|
30
|
+
failureReasons: string[];
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* True when jest reported at all, including reporting that it found nothing.
|
|
34
|
+
*
|
|
35
|
+
* "Ran and found no tests" is a legitimate answer for packages that ship
|
|
36
|
+
* without specs; "we never heard from jest" is not. Keying on the report
|
|
37
|
+
* rather than on a test count keeps `passWithNoTests` working.
|
|
38
|
+
*/
|
|
39
|
+
export declare function hasTestReport(rawOutput: string): boolean;
|
|
40
|
+
/** Count Luau tracebacks in output. */
|
|
41
|
+
export declare function countTracebacks(rawOutput: string): number;
|
|
11
42
|
/**
|
|
12
43
|
* Analyze test output for Jest failures and Luau runtime errors.
|
|
13
44
|
* Shared by both Open Cloud log fetching and local run-in-roblox output.
|
|
14
45
|
*/
|
|
15
|
-
export declare function parseTestLogs(rawOutput: string): ParsedTestLogs;
|
|
46
|
+
export declare function parseTestLogs(rawOutput: string, options?: TestOutcomeOptions): ParsedTestLogs;
|
|
16
47
|
/**
|
|
17
48
|
* Parse Jest "Tests: N failed, N passed, N total" line into structured counts.
|
|
18
49
|
* Returns undefined if no test summary line is found.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-log-parser.d.ts","sourceRoot":"","sources":["../../../src/utils/testing/test-log-parser.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"test-log-parser.d.ts","sourceRoot":"","sources":["../../../src/utils/testing/test-log-parser.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,mDAAmD;IACnD,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,kBAAuB,GAC/B;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,cAAc,EAAE,MAAM,EAAE,CAAA;CAAE,CA6BhD;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAOxD;AAED,uCAAuC;AACvC,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAKzD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,kBAAuB,GAC/B,cAAc,CAShB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,GAChB,gBAAgB,GAAG,SAAS,CAmB9B"}
|
|
@@ -1,19 +1,63 @@
|
|
|
1
1
|
import { OutputHelper } from '@quenty/cli-output-helpers';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
3
|
+
* Decide whether test output represents a pass, and say why when it does not.
|
|
4
|
+
*
|
|
5
|
+
* The single definition of the rule. Both the single-package path and the batch
|
|
6
|
+
* path route through here — they previously carried divergent copies that
|
|
7
|
+
* disagreed about tracebacks, so the same commit could pass one and fail the
|
|
8
|
+
* other.
|
|
5
9
|
*/
|
|
6
|
-
export function
|
|
10
|
+
export function evaluateTestOutcome(rawOutput, options = {}) {
|
|
7
11
|
const cleanLogs = OutputHelper.stripAnsi(rawOutput);
|
|
8
|
-
|
|
12
|
+
const failureReasons = [];
|
|
9
13
|
const failedSuites = cleanLogs.match(/Test Suites:\s*(\d+)\s+failed/);
|
|
10
14
|
const failedTests = cleanLogs.match(/Tests:\s*(\d+)\s+failed/);
|
|
11
|
-
|
|
12
|
-
(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
if (failedSuites && parseInt(failedSuites[1], 10) > 0) {
|
|
16
|
+
failureReasons.push(`${failedSuites[1]} test suite(s) failed`);
|
|
17
|
+
}
|
|
18
|
+
if (failedTests && parseInt(failedTests[1], 10) > 0) {
|
|
19
|
+
failureReasons.push(`${failedTests[1]} test(s) failed`);
|
|
20
|
+
}
|
|
21
|
+
// Tracebacks always fail. They catch use-after-free bugs that jest cannot
|
|
22
|
+
// see, since a deferred-callback crash fires outside any test.
|
|
23
|
+
const tracebacks = countTracebacks(cleanLogs);
|
|
24
|
+
if (tracebacks > 0) {
|
|
25
|
+
failureReasons.push(`${tracebacks} Luau traceback(s) — see attributed errors below`);
|
|
26
|
+
}
|
|
27
|
+
if (options.requireTestReport && !hasTestReport(cleanLogs)) {
|
|
28
|
+
failureReasons.push('no jest report in output — nothing proves any test ran');
|
|
29
|
+
}
|
|
30
|
+
return { success: failureReasons.length === 0, failureReasons };
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* True when jest reported at all, including reporting that it found nothing.
|
|
34
|
+
*
|
|
35
|
+
* "Ran and found no tests" is a legitimate answer for packages that ship
|
|
36
|
+
* without specs; "we never heard from jest" is not. Keying on the report
|
|
37
|
+
* rather than on a test count keeps `passWithNoTests` working.
|
|
38
|
+
*/
|
|
39
|
+
export function hasTestReport(rawOutput) {
|
|
40
|
+
const clean = OutputHelper.stripAnsi(rawOutput);
|
|
41
|
+
return (/Tests:\s+/.test(clean) ||
|
|
42
|
+
/Test Suites:\s+/.test(clean) ||
|
|
43
|
+
/No tests found/i.test(clean));
|
|
44
|
+
}
|
|
45
|
+
/** Count Luau tracebacks in output. */
|
|
46
|
+
export function countTracebacks(rawOutput) {
|
|
47
|
+
if (!rawOutput) {
|
|
48
|
+
return 0;
|
|
49
|
+
}
|
|
50
|
+
return OutputHelper.stripAnsi(rawOutput).match(/Stack Begin\s/g)?.length ?? 0;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Analyze test output for Jest failures and Luau runtime errors.
|
|
54
|
+
* Shared by both Open Cloud log fetching and local run-in-roblox output.
|
|
55
|
+
*/
|
|
56
|
+
export function parseTestLogs(rawOutput, options = {}) {
|
|
57
|
+
const outcome = evaluateTestOutcome(rawOutput, options);
|
|
15
58
|
return {
|
|
16
|
-
success:
|
|
59
|
+
success: outcome.success,
|
|
60
|
+
failureReasons: outcome.failureReasons,
|
|
17
61
|
logs: rawOutput,
|
|
18
62
|
testCounts: parseTestCounts(rawOutput),
|
|
19
63
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-log-parser.js","sourceRoot":"","sources":["../../../src/utils/testing/test-log-parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"test-log-parser.js","sourceRoot":"","sources":["../../../src/utils/testing/test-log-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-log-parser.test.d.ts","sourceRoot":"","sources":["../../../src/utils/testing/test-log-parser.test.ts"],"names":[],"mappings":""}
|