@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.
Files changed (53) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/commands/batch-command/batch-test-command.d.ts.map +1 -1
  3. package/dist/commands/batch-command/batch-test-command.js +18 -2
  4. package/dist/commands/batch-command/batch-test-command.js.map +1 -1
  5. package/dist/commands/test-command/test-command.d.ts.map +1 -1
  6. package/dist/commands/test-command/test-command.js +6 -4
  7. package/dist/commands/test-command/test-command.js.map +1 -1
  8. package/dist/utils/open-cloud/open-cloud-client.d.ts.map +1 -1
  9. package/dist/utils/open-cloud/open-cloud-client.js +4 -1
  10. package/dist/utils/open-cloud/open-cloud-client.js.map +1 -1
  11. package/dist/utils/testing/parsers/batch-log-parser.d.ts +13 -5
  12. package/dist/utils/testing/parsers/batch-log-parser.d.ts.map +1 -1
  13. package/dist/utils/testing/parsers/batch-log-parser.js +114 -68
  14. package/dist/utils/testing/parsers/batch-log-parser.js.map +1 -1
  15. package/dist/utils/testing/parsers/batch-log-parser.test.js +57 -5
  16. package/dist/utils/testing/parsers/batch-log-parser.test.js.map +1 -1
  17. package/dist/utils/testing/parsers/traceback-parser.d.ts +31 -0
  18. package/dist/utils/testing/parsers/traceback-parser.d.ts.map +1 -0
  19. package/dist/utils/testing/parsers/traceback-parser.js +91 -0
  20. package/dist/utils/testing/parsers/traceback-parser.js.map +1 -0
  21. package/dist/utils/testing/parsers/traceback-parser.test.d.ts +2 -0
  22. package/dist/utils/testing/parsers/traceback-parser.test.d.ts.map +1 -0
  23. package/dist/utils/testing/parsers/traceback-parser.test.js +45 -0
  24. package/dist/utils/testing/parsers/traceback-parser.test.js.map +1 -0
  25. package/dist/utils/testing/runner/test-runner.d.ts +8 -0
  26. package/dist/utils/testing/runner/test-runner.d.ts.map +1 -1
  27. package/dist/utils/testing/runner/test-runner.js +28 -3
  28. package/dist/utils/testing/runner/test-runner.js.map +1 -1
  29. package/dist/utils/testing/runner/test-runner.test.d.ts +2 -0
  30. package/dist/utils/testing/runner/test-runner.test.d.ts.map +1 -0
  31. package/dist/utils/testing/runner/test-runner.test.js +18 -0
  32. package/dist/utils/testing/runner/test-runner.test.js.map +1 -0
  33. package/dist/utils/testing/test-log-parser.d.ts +32 -1
  34. package/dist/utils/testing/test-log-parser.d.ts.map +1 -1
  35. package/dist/utils/testing/test-log-parser.js +53 -9
  36. package/dist/utils/testing/test-log-parser.js.map +1 -1
  37. package/dist/utils/testing/test-log-parser.test.d.ts +2 -0
  38. package/dist/utils/testing/test-log-parser.test.d.ts.map +1 -0
  39. package/dist/utils/testing/test-log-parser.test.js +56 -0
  40. package/dist/utils/testing/test-log-parser.test.js.map +1 -0
  41. package/package.json +2 -2
  42. package/src/commands/batch-command/batch-test-command.ts +78 -58
  43. package/src/commands/test-command/test-command.ts +7 -4
  44. package/src/utils/open-cloud/open-cloud-client.ts +4 -1
  45. package/src/utils/testing/parsers/batch-log-parser.test.ts +70 -5
  46. package/src/utils/testing/parsers/batch-log-parser.ts +141 -80
  47. package/src/utils/testing/parsers/traceback-parser.test.ts +64 -0
  48. package/src/utils/testing/parsers/traceback-parser.ts +122 -0
  49. package/src/utils/testing/runner/test-runner.test.ts +29 -0
  50. package/src/utils/testing/runner/test-runner.ts +35 -3
  51. package/src/utils/testing/test-log-parser.test.ts +70 -0
  52. package/src/utils/testing/test-log-parser.ts +80 -10
  53. package/tsconfig.tsbuildinfo +1 -1
@@ -10,27 +10,97 @@ export interface ParsedTestLogs {
10
10
  success: boolean;
11
11
  logs: string;
12
12
  testCounts?: ParsedTestCounts;
13
+ /** Why the run is not a pass. Empty when it is. */
14
+ failureReasons: string[];
15
+ }
16
+
17
+ export interface TestOutcomeOptions {
18
+ /**
19
+ * Require proof the runner ran. Off for probe scripts (--script-text), which
20
+ * legitimately produce no jest report.
21
+ */
22
+ requireTestReport?: boolean;
13
23
  }
14
24
 
15
25
  /**
16
- * Analyze test output for Jest failures and Luau runtime errors.
17
- * Shared by both Open Cloud log fetching and local run-in-roblox output.
26
+ * Decide whether test output represents a pass, and say why when it does not.
27
+ *
28
+ * The single definition of the rule. Both the single-package path and the batch
29
+ * path route through here — they previously carried divergent copies that
30
+ * disagreed about tracebacks, so the same commit could pass one and fail the
31
+ * other.
18
32
  */
19
- export function parseTestLogs(rawOutput: string): ParsedTestLogs {
33
+ export function evaluateTestOutcome(
34
+ rawOutput: string,
35
+ options: TestOutcomeOptions = {}
36
+ ): { success: boolean; failureReasons: string[] } {
20
37
  const cleanLogs = OutputHelper.stripAnsi(rawOutput);
38
+ const failureReasons: string[] = [];
21
39
 
22
- // Check for Jest-style test failures
23
40
  const failedSuites = cleanLogs.match(/Test Suites:\s*(\d+)\s+failed/);
24
41
  const failedTests = cleanLogs.match(/Tests:\s*(\d+)\s+failed/);
25
- const hasJestFailures =
26
- (failedSuites && parseInt(failedSuites[1], 10) > 0) ||
27
- (failedTests && parseInt(failedTests[1], 10) > 0);
42
+ if (failedSuites && parseInt(failedSuites[1], 10) > 0) {
43
+ failureReasons.push(`${failedSuites[1]} test suite(s) failed`);
44
+ }
45
+ if (failedTests && parseInt(failedTests[1], 10) > 0) {
46
+ failureReasons.push(`${failedTests[1]} test(s) failed`);
47
+ }
48
+
49
+ // Tracebacks always fail. They catch use-after-free bugs that jest cannot
50
+ // see, since a deferred-callback crash fires outside any test.
51
+ const tracebacks = countTracebacks(cleanLogs);
52
+ if (tracebacks > 0) {
53
+ failureReasons.push(
54
+ `${tracebacks} Luau traceback(s) — see attributed errors below`
55
+ );
56
+ }
28
57
 
29
- // Check for Luau runtime errors (stack traces)
30
- const hasRuntimeError = /Stack Begin\s/.test(cleanLogs);
58
+ if (options.requireTestReport && !hasTestReport(cleanLogs)) {
59
+ failureReasons.push(
60
+ 'no jest report in output — nothing proves any test ran'
61
+ );
62
+ }
63
+
64
+ return { success: failureReasons.length === 0, failureReasons };
65
+ }
66
+
67
+ /**
68
+ * True when jest reported at all, including reporting that it found nothing.
69
+ *
70
+ * "Ran and found no tests" is a legitimate answer for packages that ship
71
+ * without specs; "we never heard from jest" is not. Keying on the report
72
+ * rather than on a test count keeps `passWithNoTests` working.
73
+ */
74
+ export function hasTestReport(rawOutput: string): boolean {
75
+ const clean = OutputHelper.stripAnsi(rawOutput);
76
+ return (
77
+ /Tests:\s+/.test(clean) ||
78
+ /Test Suites:\s+/.test(clean) ||
79
+ /No tests found/i.test(clean)
80
+ );
81
+ }
82
+
83
+ /** Count Luau tracebacks in output. */
84
+ export function countTracebacks(rawOutput: string): number {
85
+ if (!rawOutput) {
86
+ return 0;
87
+ }
88
+ return OutputHelper.stripAnsi(rawOutput).match(/Stack Begin\s/g)?.length ?? 0;
89
+ }
90
+
91
+ /**
92
+ * Analyze test output for Jest failures and Luau runtime errors.
93
+ * Shared by both Open Cloud log fetching and local run-in-roblox output.
94
+ */
95
+ export function parseTestLogs(
96
+ rawOutput: string,
97
+ options: TestOutcomeOptions = {}
98
+ ): ParsedTestLogs {
99
+ const outcome = evaluateTestOutcome(rawOutput, options);
31
100
 
32
101
  return {
33
- success: !hasJestFailures && !hasRuntimeError,
102
+ success: outcome.success,
103
+ failureReasons: outcome.failureReasons,
34
104
  logs: rawOutput,
35
105
  testCounts: parseTestCounts(rawOutput),
36
106
  };