testeranto 0.198.0 → 0.200.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 (157) hide show
  1. package/bin/test_runner +0 -0
  2. package/bin/testeranto +0 -0
  3. package/bundle.js +2 -2
  4. package/cmd/test_runner/main.go +65 -0
  5. package/cmd/testeranto/main.go +37 -0
  6. package/dist/common/src/PM/main.js +126 -11
  7. package/dist/common/src/PM/pitonoRunner.js +54 -0
  8. package/dist/common/src/components/pure/TestPageView.js +180 -65
  9. package/dist/common/src/components/stateful/TestPage.js +50 -11
  10. package/dist/common/src/lib/abstractBase.test/index.js +1 -0
  11. package/dist/common/src/run.js +48 -82
  12. package/dist/common/src/{build.js → testeranto.js} +107 -55
  13. package/dist/common/src/utils/golingvuMetafile.js +116 -0
  14. package/dist/common/src/utils/logFiles.js +2 -1
  15. package/dist/common/src/utils/pitonoMetafile.js +67 -0
  16. package/dist/common/src/utils.js +40 -1
  17. package/dist/common/testeranto.config.js +23 -21
  18. package/dist/common/tsconfig.common.tsbuildinfo +1 -1
  19. package/dist/module/src/PM/main.js +126 -11
  20. package/dist/module/src/PM/pitonoRunner.js +47 -0
  21. package/dist/module/src/components/pure/TestPageView.js +180 -65
  22. package/dist/module/src/components/stateful/TestPage.js +50 -11
  23. package/dist/module/src/lib/abstractBase.test/index.js +1 -0
  24. package/dist/module/src/run.js +49 -45
  25. package/dist/module/src/{build.js → testeranto.js} +107 -55
  26. package/dist/module/src/utils/golingvuMetafile.js +109 -0
  27. package/dist/module/src/utils/logFiles.js +2 -1
  28. package/dist/module/src/utils/pitonoMetafile.js +60 -0
  29. package/dist/module/src/utils.js +40 -1
  30. package/dist/module/testeranto.config.js +23 -21
  31. package/dist/module/tsconfig.module.tsbuildinfo +1 -1
  32. package/dist/prebuild/App.js +81 -17
  33. package/dist/types/src/PM/main.d.ts +2 -0
  34. package/dist/types/src/PM/pitonoRunner.d.ts +7 -0
  35. package/dist/types/src/Types.d.ts +1 -1
  36. package/dist/types/src/run.d.ts +0 -1
  37. package/dist/types/src/utils/golingvuMetafile.d.ts +19 -0
  38. package/dist/types/src/utils/logFiles.d.ts +5 -1
  39. package/dist/types/src/utils/pitonoMetafile.d.ts +7 -0
  40. package/dist/types/src/utils.d.ts +5 -0
  41. package/dist/types/tsconfig.types.tsbuildinfo +1 -1
  42. package/docs/index.md +13 -13
  43. package/example/test_example.py +106 -0
  44. package/go.mod +3 -0
  45. package/package.json +14 -14
  46. package/pitono/__init__.py +54 -0
  47. package/pitono/base_given.py +131 -0
  48. package/pitono/base_suite.py +95 -0
  49. package/pitono/base_then.py +50 -0
  50. package/pitono/base_when.py +52 -0
  51. package/pitono/core_generator.py +110 -0
  52. package/pitono/pitono.egg-info/PKG-INFO +17 -0
  53. package/pitono/pitono.egg-info/SOURCES.txt +7 -0
  54. package/pitono/pitono.egg-info/dependency_links.txt +1 -0
  55. package/pitono/pitono.egg-info/entry_points.txt +2 -0
  56. package/pitono/pitono.egg-info/top_level.txt +1 -0
  57. package/pitono/pyproject.toml +26 -0
  58. package/pitono/setup.py +40 -0
  59. package/pitono/simple_adapter.py +24 -0
  60. package/pitono/types.py +78 -0
  61. package/sampleMetafile.json +56 -0
  62. package/src/PM/main.ts +146 -17
  63. package/src/PM/pitonoRunner.ts +49 -0
  64. package/src/Types.ts +1 -1
  65. package/src/components/pure/TestPageView.tsx +175 -8
  66. package/src/components/stateful/TestPage.tsx +57 -16
  67. package/src/core/types.go +36 -0
  68. package/src/golingvu/README.md +3 -0
  69. package/src/golingvu/base_given.go +76 -0
  70. package/src/golingvu/base_suite.go +39 -0
  71. package/src/golingvu/base_suite_test.go +197 -0
  72. package/src/golingvu/base_then.go +21 -0
  73. package/src/golingvu/base_when.go +21 -0
  74. package/src/golingvu/golingvu.go +179 -0
  75. package/src/golingvu/test_adapter.go +33 -0
  76. package/src/golingvu/types.go +86 -0
  77. package/src/lib/abstractBase.test/index.ts +1 -0
  78. package/src/pitono/README.md +3 -0
  79. package/src/run.ts +48 -48
  80. package/src/templates/frontpage.html +26 -17
  81. package/src/{build.ts → testeranto.ts} +128 -58
  82. package/src/utils/golingvuMetafile.ts +165 -0
  83. package/src/utils/logFiles.ts +2 -1
  84. package/src/utils/pitonoMetafile.ts +68 -0
  85. package/src/utils.ts +38 -1
  86. package/testeranto/App.js +81 -17
  87. package/testeranto/metafiles/golang/core.json +72 -0
  88. package/testeranto/metafiles/node/core.json +21 -459
  89. package/testeranto/metafiles/pure/core.json +18 -119
  90. package/testeranto/metafiles/web/core.json +37 -16797
  91. package/testeranto/reports/core/config.json +8 -40
  92. package/testeranto/reports/core/src/lib/BaseSuite.test/node.test/node/lint_errors.txt +6 -0
  93. package/testeranto/reports/core/src/lib/BaseSuite.test/node.test/node/prompt.txt +12 -1
  94. package/testeranto/reports/core/src/lib/BaseSuite.test/pure.test/pure/lint_errors.txt +2 -0
  95. package/testeranto/reports/core/src/lib/BaseSuite.test/pure.test/pure/prompt.txt +11 -1
  96. package/testeranto/reports/core/src/lib/BaseSuite.test/web.test/web/lint_errors.txt +2 -0
  97. package/testeranto/reports/core/src/lib/BaseSuite.test/web.test/web/prompt.txt +13 -3
  98. package/testeranto/reports/core/summary.json +9 -45
  99. package/testeranto.config.ts +25 -21
  100. package/tsc.log +46 -7
  101. package/dist/common/src/lib/mocks.test.js +0 -11
  102. package/dist/module/src/lib/mocks.test.js +0 -11
  103. package/dist/prebuild/build.mjs +0 -578
  104. package/dist/prebuild/run.mjs +0 -2290
  105. package/dist/tsconfig.tsbuildinfo +0 -1
  106. package/dist/types/src/lib/mocks.test.d.ts +0 -0
  107. package/src/lib/mocks.test.ts +0 -11
  108. package/testeranto/reports/core/src/Pure.test/pure/exit.log +0 -0
  109. package/testeranto/reports/core/src/Pure.test/pure/lint_errors.txt +0 -0
  110. package/testeranto/reports/core/src/Pure.test/pure/message.txt +0 -17
  111. package/testeranto/reports/core/src/Pure.test/pure/prompt.txt +0 -14
  112. package/testeranto/reports/core/src/Pure.test/pure/type_errors.txt +0 -66
  113. package/testeranto/reports/core/src/components/pure/FeaturesReporterView.test/index/web/debug.log +0 -0
  114. package/testeranto/reports/core/src/components/pure/FeaturesReporterView.test/index/web/error.log +0 -67
  115. package/testeranto/reports/core/src/components/pure/FeaturesReporterView.test/index/web/exit.log +0 -1
  116. package/testeranto/reports/core/src/components/pure/FeaturesReporterView.test/index/web/info.log +0 -2
  117. package/testeranto/reports/core/src/components/pure/FeaturesReporterView.test/index/web/lint_errors.txt +0 -0
  118. package/testeranto/reports/core/src/components/pure/FeaturesReporterView.test/index/web/message.txt +0 -17
  119. package/testeranto/reports/core/src/components/pure/FeaturesReporterView.test/index/web/prompt.txt +0 -16
  120. package/testeranto/reports/core/src/components/pure/FeaturesReporterView.test/index/web/tests.json +0 -68
  121. package/testeranto/reports/core/src/components/pure/FeaturesReporterView.test/index/web/type_errors.txt +0 -56
  122. package/testeranto/reports/core/src/components/pure/FeaturesReporterView.test/index/web/warn.log +0 -0
  123. package/testeranto/reports/core/src/components/pure/ProjectPageView.test/index/web/debug.log +0 -0
  124. package/testeranto/reports/core/src/components/pure/ProjectPageView.test/index/web/error.log +0 -22
  125. package/testeranto/reports/core/src/components/pure/ProjectPageView.test/index/web/exit.log +0 -1
  126. package/testeranto/reports/core/src/components/pure/ProjectPageView.test/index/web/info.log +0 -2
  127. package/testeranto/reports/core/src/components/pure/ProjectPageView.test/index/web/lint_errors.txt +0 -13
  128. package/testeranto/reports/core/src/components/pure/ProjectPageView.test/index/web/message.txt +0 -17
  129. package/testeranto/reports/core/src/components/pure/ProjectPageView.test/index/web/prompt.txt +0 -16
  130. package/testeranto/reports/core/src/components/pure/ProjectPageView.test/index/web/tests.json +0 -88
  131. package/testeranto/reports/core/src/components/pure/ProjectPageView.test/index/web/type_errors.txt +0 -45
  132. package/testeranto/reports/core/src/components/pure/ProjectPageView.test/index/web/warn.log +0 -0
  133. package/testeranto/reports/core/src/components/pure/TestPageView.test/index/web/debug.log +0 -0
  134. package/testeranto/reports/core/src/components/pure/TestPageView.test/index/web/error.log +0 -0
  135. package/testeranto/reports/core/src/components/pure/TestPageView.test/index/web/exit.log +0 -1
  136. package/testeranto/reports/core/src/components/pure/TestPageView.test/index/web/info.log +0 -2
  137. package/testeranto/reports/core/src/components/pure/TestPageView.test/index/web/lint_errors.txt +0 -47
  138. package/testeranto/reports/core/src/components/pure/TestPageView.test/index/web/message.txt +0 -17
  139. package/testeranto/reports/core/src/components/pure/TestPageView.test/index/web/prompt.txt +0 -17
  140. package/testeranto/reports/core/src/components/pure/TestPageView.test/index/web/tests.json +0 -57
  141. package/testeranto/reports/core/src/components/pure/TestPageView.test/index/web/type_errors.txt +0 -99
  142. package/testeranto/reports/core/src/components/pure/TestPageView.test/index/web/warn.log +0 -0
  143. package/testeranto/reports/core/src/lib/TipoSkripto.test/TipoSkripto/node/exit.log +0 -1
  144. package/testeranto/reports/core/src/lib/TipoSkripto.test/TipoSkripto/node/lint_errors.txt +0 -0
  145. package/testeranto/reports/core/src/lib/TipoSkripto.test/TipoSkripto/node/message.txt +0 -17
  146. package/testeranto/reports/core/src/lib/TipoSkripto.test/TipoSkripto/node/prompt.txt +0 -17
  147. package/testeranto/reports/core/src/lib/TipoSkripto.test/TipoSkripto/node/stderr.log +0 -18
  148. package/testeranto/reports/core/src/lib/TipoSkripto.test/TipoSkripto/node/stdout.log +0 -0
  149. package/testeranto/reports/core/src/lib/TipoSkripto.test/TipoSkripto/node/type_errors.txt +0 -32
  150. package/testeranto/reports/core/src/lib/pmProxy.test/index/node/exit.log +0 -1
  151. package/testeranto/reports/core/src/lib/pmProxy.test/index/node/lint_errors.txt +0 -15
  152. package/testeranto/reports/core/src/lib/pmProxy.test/index/node/message.txt +0 -17
  153. package/testeranto/reports/core/src/lib/pmProxy.test/index/node/prompt.txt +0 -17
  154. package/testeranto/reports/core/src/lib/pmProxy.test/index/node/stderr.log +0 -66
  155. package/testeranto/reports/core/src/lib/pmProxy.test/index/node/stdout.log +0 -10
  156. package/testeranto/reports/core/src/lib/pmProxy.test/index/node/type_errors.txt +0 -47
  157. /package/dist/types/src/{build.d.ts → testeranto.d.ts} +0 -0
@@ -48,6 +48,13 @@ function runtimeLogs(runtime, reportDest) {
48
48
  exit: fs.createWriteStream(`${safeDest}/exit.log`),
49
49
  };
50
50
  }
51
+ else if (runtime === "pitono") {
52
+ return {
53
+ stdout: fs.createWriteStream(`${safeDest}/stdout.log`),
54
+ stderr: fs.createWriteStream(`${safeDest}/stderr.log`),
55
+ exit: fs.createWriteStream(`${safeDest}/exit.log`),
56
+ };
57
+ }
51
58
  else {
52
59
  throw `unknown runtime: ${runtime}`;
53
60
  }
@@ -780,6 +787,32 @@ export class PM_Main extends PM_WithEslintAndTsc {
780
787
  // }
781
788
  // }
782
789
  };
790
+ this.launchPitono = async (src, dest) => {
791
+ console.log(ansiC.green(ansiC.inverse(`pitono < ${src}`)));
792
+ this.bddTestIsRunning(src);
793
+ const reportDest = `testeranto/reports/${this.name}/${src
794
+ .split(".")
795
+ .slice(0, -1)
796
+ .join(".")}/pitono`;
797
+ if (!fs.existsSync(reportDest)) {
798
+ fs.mkdirSync(reportDest, { recursive: true });
799
+ }
800
+ const logs = createLogStreams(reportDest, "node"); // Use node-style logs for pitono
801
+ try {
802
+ // Execute the Python test using the pitono runner
803
+ const { PitonoRunner } = await import('./pitonoRunner');
804
+ const runner = new PitonoRunner(this.configs, this.name);
805
+ await runner.run();
806
+ this.bddTestIsNowDone(src, 0);
807
+ statusMessagePretty(0, src, "pitono");
808
+ }
809
+ catch (error) {
810
+ logs.writeExitCode(-1, error);
811
+ console.log(ansiC.red(ansiC.inverse(`${src} errored with: ${error}. Check logs for more info`)));
812
+ this.bddTestIsNowDone(src, -1);
813
+ statusMessagePretty(-1, src, "pitono");
814
+ }
815
+ };
783
816
  this.launchWeb = async (src, dest) => {
784
817
  console.log(ansiC.green(ansiC.inverse(`web < ${src}`)));
785
818
  this.bddTestIsRunning(src);
@@ -1352,7 +1385,7 @@ import('${d}').then(async (x) => {
1352
1385
  console.error(e);
1353
1386
  console.error("could not start chrome via puppeter. Check this path: ", executablePath);
1354
1387
  }
1355
- const { nodeEntryPoints, webEntryPoints, pureEntryPoints } = this.getRunnables(this.configs.tests, this.name);
1388
+ const { nodeEntryPoints, webEntryPoints, pureEntryPoints, pitonoEntryPoints } = this.getRunnables(this.configs.tests, this.name);
1356
1389
  [
1357
1390
  [
1358
1391
  nodeEntryPoints,
@@ -1378,9 +1411,31 @@ import('${d}').then(async (x) => {
1378
1411
  this.importMetafileWatcher = w;
1379
1412
  },
1380
1413
  ],
1414
+ [
1415
+ pitonoEntryPoints,
1416
+ this.launchPitono,
1417
+ "pitono",
1418
+ (w) => {
1419
+ this.pitonoMetafileWatcher = w;
1420
+ },
1421
+ ],
1381
1422
  ].forEach(async ([eps, launcher, runtime, watcher]) => {
1382
- const metafile = `./testeranto/metafiles/${runtime}/${this.name}.json`;
1383
- await pollForFile(metafile);
1423
+ let metafile;
1424
+ if (runtime === "pitono") {
1425
+ metafile = `./testeranto/metafiles/python/core.json`;
1426
+ // Ensure the directory exists before trying to watch
1427
+ const metafileDir = path.dirname(metafile);
1428
+ if (!fs.existsSync(metafileDir)) {
1429
+ fs.mkdirSync(metafileDir, { recursive: true });
1430
+ }
1431
+ }
1432
+ else {
1433
+ metafile = `./testeranto/metafiles/${runtime}/${this.name}.json`;
1434
+ }
1435
+ // Only poll for file if it's not a pitono runtime
1436
+ if (runtime !== "pitono") {
1437
+ await pollForFile(metafile);
1438
+ }
1384
1439
  Object.entries(eps).forEach(async ([inputFile, outputFile]) => {
1385
1440
  // await pollForFile(outputFile);\
1386
1441
  this.launchers[inputFile] = () => launcher(inputFile, outputFile);
@@ -1401,10 +1456,37 @@ import('${d}').then(async (x) => {
1401
1456
  }
1402
1457
  });
1403
1458
  this.metafileOutputs(runtime);
1404
- watcher(watch(metafile, async (e, filename) => {
1405
- console.log(ansiC.yellow(ansiC.inverse(`< ${e} ${filename} (${runtime})`)));
1406
- this.metafileOutputs(runtime);
1407
- }));
1459
+ // For pitono, we need to wait for the file to be created
1460
+ if (runtime === "pitono") {
1461
+ // Use polling to wait for the file to exist
1462
+ const checkFileExists = () => {
1463
+ if (fs.existsSync(metafile)) {
1464
+ console.log(ansiC.green(ansiC.inverse(`Pitono metafile found: ${metafile}`)));
1465
+ // Set up the watcher once the file exists
1466
+ watcher(watch(metafile, async (e, filename) => {
1467
+ console.log(ansiC.yellow(ansiC.inverse(`< ${e} ${filename} (${runtime})`)));
1468
+ this.metafileOutputs(runtime);
1469
+ }));
1470
+ // Read the metafile immediately
1471
+ this.metafileOutputs(runtime);
1472
+ }
1473
+ else {
1474
+ // Check again after a delay
1475
+ setTimeout(checkFileExists, 1000);
1476
+ }
1477
+ };
1478
+ // Start checking for the file
1479
+ checkFileExists();
1480
+ }
1481
+ else {
1482
+ // For other runtimes, only set up watcher if the file exists
1483
+ if (fs.existsSync(metafile)) {
1484
+ watcher(watch(metafile, async (e, filename) => {
1485
+ console.log(ansiC.yellow(ansiC.inverse(`< ${e} ${filename} (${runtime})`)));
1486
+ this.metafileOutputs(runtime);
1487
+ }));
1488
+ }
1489
+ }
1408
1490
  });
1409
1491
  // Object.keys(this.configs.externalTests).forEach((et) => {
1410
1492
  // this.launchExternalTest(et, this.configs.externalTests[et]);
@@ -1446,6 +1528,9 @@ import('${d}').then(async (x) => {
1446
1528
  this.nodeMetafileWatcher.close();
1447
1529
  this.webMetafileWatcher.close();
1448
1530
  this.importMetafileWatcher.close();
1531
+ if (this.pitonoMetafileWatcher) {
1532
+ this.pitonoMetafileWatcher.close();
1533
+ }
1449
1534
  // Close any remaining log streams
1450
1535
  Object.values(this.logStreams || {}).forEach((logs) => logs.closeAll());
1451
1536
  // Close WebSocket server
@@ -1464,11 +1549,41 @@ import('${d}').then(async (x) => {
1464
1549
  this.checkForShutdown();
1465
1550
  }
1466
1551
  async metafileOutputs(platform) {
1467
- const metafile = JSON.parse(fs
1468
- .readFileSync(`./testeranto/metafiles/${platform}/${this.name}.json`)
1469
- .toString()).metafile;
1470
- if (!metafile)
1552
+ let metafilePath;
1553
+ if (platform === "pitono") {
1554
+ metafilePath = `./testeranto/metafiles/python/core.json`;
1555
+ }
1556
+ else {
1557
+ metafilePath = `./testeranto/metafiles/${platform}/${this.name}.json`;
1558
+ }
1559
+ // Check if the file exists
1560
+ if (!fs.existsSync(metafilePath)) {
1561
+ if (platform === "pitono") {
1562
+ console.log(ansiC.yellow(ansiC.inverse(`Pitono metafile not found yet: ${metafilePath}`)));
1563
+ }
1564
+ return;
1565
+ }
1566
+ let metafile;
1567
+ try {
1568
+ const fileContent = fs.readFileSync(metafilePath).toString();
1569
+ const parsedData = JSON.parse(fileContent);
1570
+ // Handle different metafile structures
1571
+ if (platform === "pitono") {
1572
+ // Pitono metafile might be the entire content or have a different structure
1573
+ metafile = parsedData.metafile || parsedData;
1574
+ }
1575
+ else {
1576
+ metafile = parsedData.metafile;
1577
+ }
1578
+ if (!metafile) {
1579
+ console.log(ansiC.yellow(ansiC.inverse(`No metafile found in ${metafilePath}`)));
1580
+ return;
1581
+ }
1582
+ }
1583
+ catch (error) {
1584
+ console.error(`Error reading metafile at ${metafilePath}:`, error);
1471
1585
  return;
1586
+ }
1472
1587
  const outputs = metafile.outputs;
1473
1588
  Object.keys(outputs).forEach(async (k) => {
1474
1589
  const pattern = `testeranto/bundles/${platform}/${this.name}/${this.configs.src}`;
@@ -0,0 +1,47 @@
1
+ import { execSync } from 'child_process';
2
+ import path from 'path';
3
+ import fs from 'fs';
4
+ export class PitonoRunner {
5
+ constructor(config, testName) {
6
+ this.config = config;
7
+ this.testName = testName;
8
+ }
9
+ async run() {
10
+ const coreJsonPath = path.join(process.cwd(), 'testeranto', 'pitono', this.testName, 'core.json');
11
+ // Wait for the core.json file to be created with a timeout
12
+ const maxWaitTime = 10000; // 10 seconds
13
+ const startTime = Date.now();
14
+ while (!fs.existsSync(coreJsonPath) && (Date.now() - startTime) < maxWaitTime) {
15
+ await new Promise(resolve => setTimeout(resolve, 100));
16
+ }
17
+ if (!fs.existsSync(coreJsonPath)) {
18
+ console.error(`Pitono core.json not found at: ${coreJsonPath} after waiting ${maxWaitTime}ms`);
19
+ return;
20
+ }
21
+ try {
22
+ const coreData = JSON.parse(fs.readFileSync(coreJsonPath, 'utf-8'));
23
+ const entryPoints = coreData.entryPoints;
24
+ for (const entryPoint of entryPoints) {
25
+ try {
26
+ console.log(`Running pitono test: ${entryPoint}`);
27
+ // Use python to execute the test file
28
+ const absolutePath = path.resolve(entryPoint);
29
+ // Check if the file exists
30
+ if (!fs.existsSync(absolutePath)) {
31
+ console.error(`Pitono test file not found: ${absolutePath}`);
32
+ continue;
33
+ }
34
+ execSync(`python "${absolutePath}"`, { stdio: 'inherit' });
35
+ console.log(`Pitono test completed: ${entryPoint}`);
36
+ }
37
+ catch (error) {
38
+ console.error(`Pitono test failed: ${entryPoint}`, error);
39
+ throw error;
40
+ }
41
+ }
42
+ }
43
+ catch (error) {
44
+ console.error(`Error reading or parsing core.json: ${error}`);
45
+ }
46
+ }
47
+ }
@@ -44,9 +44,44 @@ export const TestPageView = ({ projectName, testName, decodedTestPath, runtime,
44
44
  const [expandedSections, setExpandedSections] = useState({
45
45
  standardLogs: true,
46
46
  runtimeLogs: true,
47
- sourceFiles: true
47
+ sourceFiles: true,
48
+ buildErrors: true,
48
49
  });
49
50
  const [isNavbarCollapsed, setIsNavbarCollapsed] = useState(false);
51
+ // Extract build errors and warnings relevant to this test
52
+ const [buildErrors, setBuildErrors] = useState({ errors: [], warnings: [] });
53
+ useEffect(() => {
54
+ var _a, _b, _c;
55
+ const metafile = (_a = logs.build_logs) === null || _a === void 0 ? void 0 : _a.metafile;
56
+ if (!metafile) {
57
+ setBuildErrors({ errors: [], warnings: [] });
58
+ return;
59
+ }
60
+ const sourceFilesSet = new Set();
61
+ // Collect all input files from metafile outputs related to this test
62
+ Object.entries(metafile.outputs || {}).forEach(([outputPath, output]) => {
63
+ // Normalize paths for comparison
64
+ const normalizedTestName = testName.replace(/\\/g, '/');
65
+ const normalizedEntryPoint = output.entryPoint ? output.entryPoint.replace(/\\/g, '/') : '';
66
+ if (normalizedEntryPoint.includes(normalizedTestName)) {
67
+ Object.keys(output.inputs || {}).forEach((inputPath) => {
68
+ sourceFilesSet.add(inputPath.replace(/\\/g, '/'));
69
+ });
70
+ }
71
+ });
72
+ // Filter errors and warnings to those originating from source files of this test
73
+ const filteredErrors = (((_b = logs.build_logs) === null || _b === void 0 ? void 0 : _b.errors) || []).filter((err) => {
74
+ if (!err.location || !err.location.file)
75
+ return false;
76
+ return sourceFilesSet.has(err.location.file.replace(/\\/g, '/'));
77
+ });
78
+ const filteredWarnings = (((_c = logs.build_logs) === null || _c === void 0 ? void 0 : _c.warnings) || []).filter((warn) => {
79
+ if (!warn.location || !warn.location.file)
80
+ return false;
81
+ return sourceFilesSet.has(warn.location.file.replace(/\\/g, '/'));
82
+ });
83
+ setBuildErrors({ errors: filteredErrors, warnings: filteredWarnings });
84
+ }, [logs, testName]);
50
85
  // Update customMessage when logs change
51
86
  useEffect(() => {
52
87
  if (typeof logs['message.txt'] === 'string' && logs['message.txt'].trim()) {
@@ -87,67 +122,94 @@ export const TestPageView = ({ projectName, testName, decodedTestPath, runtime,
87
122
  }
88
123
  };
89
124
  const renderTestResults = (testData) => {
90
- return (React.createElement("div", { className: "test-results" }, testData.givens.map((given, i) => (React.createElement("div", { key: i, className: "mb-4 card" },
91
- React.createElement("div", { className: "card-header bg-primary text-white" },
92
- React.createElement("div", { className: "d-flex justify-content-between align-items-center" },
93
- React.createElement("div", null,
94
- React.createElement("h4", null,
95
- "Given: ",
96
- given.name),
97
- given.features && given.features.length > 0 && (React.createElement("div", { className: "mt-1" },
98
- React.createElement("small", null, "Features:"),
99
- React.createElement("ul", { className: "list-unstyled" }, given.features.map((feature, fi) => (React.createElement("li", { key: fi }, feature.startsWith("http") ? (React.createElement("a", { href: feature, target: "_blank", rel: "noopener noreferrer", className: "text-white" }, new URL(feature).hostname)) : (React.createElement("span", { className: "text-white" }, feature))))))))),
100
- given.artifacts && given.artifacts.length > 0 && (React.createElement("div", { className: "dropdown" },
101
- React.createElement("button", { className: "btn btn-sm btn-light dropdown-toggle", type: "button", "data-bs-toggle": "dropdown" },
102
- "Artifacts (",
103
- given.artifacts.length,
104
- ")"),
105
- React.createElement("ul", { className: "dropdown-menu dropdown-menu-end" }, given.artifacts.map((artifact, ai) => (React.createElement("li", { key: ai },
106
- React.createElement("a", { className: "dropdown-item", href: `reports/${projectName}/${testName
107
- .split(".")
108
- .slice(0, -1)
109
- .join(".")}/${runtime}/${artifact}`, target: "_blank", rel: "noopener noreferrer" }, artifact.split("/").pop()))))))))),
110
- React.createElement("div", { className: "card-body" },
111
- given.whens.map((when, j) => (React.createElement("div", { key: `w-${j}`, className: `p-3 mb-2 ${when.error
112
- ? "bg-danger text-white"
113
- : "bg-success text-white"}` },
114
- React.createElement("div", { className: "d-flex justify-content-between align-items-start" },
125
+ return (React.createElement("div", { className: "test-results" },
126
+ testData.givens.map((given, i) => (React.createElement("div", { key: i, className: "mb-4 card" },
127
+ React.createElement("div", { className: "card-header bg-primary text-white" },
128
+ React.createElement("div", { className: "d-flex justify-content-between align-items-center" },
115
129
  React.createElement("div", null,
116
- React.createElement("div", null,
117
- React.createElement("strong", null, "When:"),
118
- " ",
119
- when.name,
120
- when.features && when.features.length > 0 && (React.createElement("div", { className: "mt-2" },
121
- React.createElement("small", null, "Features:"),
122
- React.createElement("ul", { className: "list-unstyled" }, when.features.map((feature, fi) => (React.createElement("li", { key: fi }, feature.startsWith("http") ? (React.createElement("a", { href: feature, target: "_blank", rel: "noopener noreferrer" }, new URL(feature).hostname)) : (feature))))))),
123
- when.error && React.createElement("pre", { className: "mt-2" }, when.error))),
124
- when.artifacts && when.artifacts.length > 0 && (React.createElement("div", { className: "ms-3" },
125
- React.createElement("strong", null, "Artifacts:"),
126
- React.createElement("ul", { className: "list-unstyled" }, when.artifacts.map((artifact, ai) => (React.createElement("li", { key: ai },
127
- React.createElement("a", { href: `reports/${projectName}/${testName
130
+ React.createElement("h4", null,
131
+ "Given: ",
132
+ given.name),
133
+ given.features && given.features.length > 0 && (React.createElement("div", { className: "mt-1" },
134
+ React.createElement("small", null, "Features:"),
135
+ React.createElement("ul", { className: "list-unstyled" }, given.features.map((feature, fi) => (React.createElement("li", { key: fi }, feature.startsWith("http") ? (React.createElement("a", { href: feature, target: "_blank", rel: "noopener noreferrer", className: "text-white" }, new URL(feature).hostname)) : (React.createElement("span", { className: "text-white" }, feature))))))))),
136
+ given.artifacts && given.artifacts.length > 0 && (React.createElement("div", { className: "dropdown" },
137
+ React.createElement("button", { className: "btn btn-sm btn-light dropdown-toggle", type: "button", "data-bs-toggle": "dropdown" },
138
+ "Artifacts (",
139
+ given.artifacts.length,
140
+ ")"),
141
+ React.createElement("ul", { className: "dropdown-menu dropdown-menu-end" }, given.artifacts.map((artifact, ai) => (React.createElement("li", { key: ai },
142
+ React.createElement("a", { className: "dropdown-item", href: `reports/${projectName}/${testName
128
143
  .split(".")
129
144
  .slice(0, -1)
130
- .join(".")}/${runtime}/${artifact}`, target: "_blank", className: "text-white", rel: "noopener noreferrer" }, artifact.split("/").pop()))))))))))),
131
- given.thens.map((then, k) => (React.createElement("div", { key: `t-${k}`, className: `p-3 mb-2 ${then.error
132
- ? "bg-danger text-white"
133
- : "bg-success text-white"}` },
134
- React.createElement("div", { className: "d-flex justify-content-between align-items-start" },
135
- React.createElement("div", null,
145
+ .join(".")}/${runtime}/${artifact}`, target: "_blank", rel: "noopener noreferrer" }, artifact.split("/").pop()))))))))),
146
+ React.createElement("div", { className: "card-body" },
147
+ given.whens.map((when, j) => (React.createElement("div", { key: `w-${j}`, className: `p-3 mb-2 ${when.error
148
+ ? "bg-danger text-white"
149
+ : "bg-success text-white"}` },
150
+ React.createElement("div", { className: "d-flex justify-content-between align-items-start" },
136
151
  React.createElement("div", null,
137
- React.createElement("strong", null, "Then:"),
138
- " ",
139
- then.name,
140
- then.features && then.features.length > 0 && (React.createElement("div", { className: "mt-2" },
141
- React.createElement("small", null, "Features:"),
142
- React.createElement("ul", { className: "list-unstyled" }, then.features.map((feature, fi) => (React.createElement("li", { key: fi }, feature.startsWith("http") ? (React.createElement("a", { href: feature, target: "_blank", rel: "noopener noreferrer" }, new URL(feature).hostname)) : (feature))))))),
143
- then.error && React.createElement("pre", { className: "mt-2" }, then.error))),
144
- then.artifacts && then.artifacts.length > 0 && (React.createElement("div", { className: "ms-3" },
145
- React.createElement("strong", null, "Artifacts:"),
146
- React.createElement("ul", { className: "list-unstyled" }, then.artifacts.map((artifact, ai) => (React.createElement("li", { key: ai },
147
- React.createElement("a", { href: `reports/${projectName}/${testName
148
- .split(".")
149
- .slice(0, -1)
150
- .join(".")}/${runtime}/${artifact}`, target: "_blank", className: "text-white", rel: "noopener noreferrer" }, artifact.split("/").pop())))))))))))))))));
152
+ React.createElement("div", null,
153
+ React.createElement("strong", null, "When:"),
154
+ " ",
155
+ when.name,
156
+ when.features && when.features.length > 0 && (React.createElement("div", { className: "mt-2" },
157
+ React.createElement("small", null, "Features:"),
158
+ React.createElement("ul", { className: "list-unstyled" }, when.features.map((feature, fi) => (React.createElement("li", { key: fi }, feature.startsWith("http") ? (React.createElement("a", { href: feature, target: "_blank", rel: "noopener noreferrer" }, new URL(feature).hostname)) : (feature))))))),
159
+ when.error && React.createElement("pre", { className: "mt-2" }, when.error))),
160
+ when.artifacts && when.artifacts.length > 0 && (React.createElement("div", { className: "ms-3" },
161
+ React.createElement("strong", null, "Artifacts:"),
162
+ React.createElement("ul", { className: "list-unstyled" }, when.artifacts.map((artifact, ai) => (React.createElement("li", { key: ai },
163
+ React.createElement("a", { href: `reports/${projectName}/${testName
164
+ .split(".")
165
+ .slice(0, -1)
166
+ .join(".")}/${runtime}/${artifact}`, target: "_blank", className: "text-white", rel: "noopener noreferrer" }, artifact.split("/").pop()))))))))))),
167
+ given.thens.map((then, k) => (React.createElement("div", { key: `t-${k}`, className: `p-3 mb-2 ${then.error
168
+ ? "bg-danger text-white"
169
+ : "bg-success text-white"}` },
170
+ React.createElement("div", { className: "d-flex justify-content-between align-items-start" },
171
+ React.createElement("div", null,
172
+ React.createElement("div", null,
173
+ React.createElement("strong", null, "Then:"),
174
+ " ",
175
+ then.name,
176
+ then.features && then.features.length > 0 && (React.createElement("div", { className: "mt-2" },
177
+ React.createElement("small", null, "Features:"),
178
+ React.createElement("ul", { className: "list-unstyled" }, then.features.map((feature, fi) => (React.createElement("li", { key: fi }, feature.startsWith("http") ? (React.createElement("a", { href: feature, target: "_blank", rel: "noopener noreferrer" }, new URL(feature).hostname)) : (feature))))))),
179
+ then.error && React.createElement("pre", { className: "mt-2" }, then.error))),
180
+ then.artifacts && then.artifacts.length > 0 && (React.createElement("div", { className: "ms-3" },
181
+ React.createElement("strong", null, "Artifacts:"),
182
+ React.createElement("ul", { className: "list-unstyled" }, then.artifacts.map((artifact, ai) => (React.createElement("li", { key: ai },
183
+ React.createElement("a", { href: `reports/${projectName}/${testName
184
+ .split(".")
185
+ .slice(0, -1)
186
+ .join(".")}/${runtime}/${artifact}`, target: "_blank", className: "text-white", rel: "noopener noreferrer" }, artifact.split("/").pop()))))))))))))))),
187
+ (buildErrors.errors.length > 0 || buildErrors.warnings.length > 0) && (React.createElement("div", { className: "mb-4 card border-danger" },
188
+ React.createElement("div", { className: "card-header bg-danger text-white" },
189
+ React.createElement("h4", null, "Build Errors and Warnings")),
190
+ React.createElement("div", { className: "card-body" },
191
+ buildErrors.errors.length > 0 && (React.createElement(React.Fragment, null,
192
+ React.createElement("h5", null, "Errors"),
193
+ React.createElement("ul", null, buildErrors.errors.map((error, idx) => (React.createElement("li", { key: `build-error-${idx}` },
194
+ React.createElement("strong", null, error.text),
195
+ error.location && (React.createElement("div", null,
196
+ "File: ",
197
+ error.location.file,
198
+ " Line: ",
199
+ error.location.line,
200
+ " Column: ",
201
+ error.location.column)))))))),
202
+ buildErrors.warnings.length > 0 && (React.createElement(React.Fragment, null,
203
+ React.createElement("h5", null, "Warnings"),
204
+ React.createElement("ul", null, buildErrors.warnings.map((warning, idx) => (React.createElement("li", { key: `build-warning-${idx}` },
205
+ React.createElement("strong", null, warning.text),
206
+ warning.location && (React.createElement("div", null,
207
+ "File: ",
208
+ warning.location.file,
209
+ " Line: ",
210
+ warning.location.line,
211
+ " Column: ",
212
+ warning.location.column)))))))))))));
151
213
  };
152
214
  console.log("Rendering TestPageView with logs:", {
153
215
  logKeys: Object.keys(logs),
@@ -244,10 +306,10 @@ export const TestPageView = ({ projectName, testName, decodedTestPath, runtime,
244
306
  React.createElement("i", { className: `bi bi-chevron-${expandedSections.standardLogs ? 'down' : 'right'} me-1` }),
245
307
  React.createElement("span", null, "Standard Logs")),
246
308
  expandedSections.standardLogs && (React.createElement("div", null, Object.values(STANDARD_LOGS).map((logName) => {
247
- const logContent = logs[logName];
309
+ const logContent = logs ? logs[logName] : undefined;
248
310
  const exists = logContent !== undefined &&
249
311
  ((typeof logContent === "string" && logContent.trim() !== "") ||
250
- (typeof logContent === "object" && Object.keys(logContent).length > 0));
312
+ (typeof logContent === "object" && logContent !== null && Object.keys(logContent).length > 0));
251
313
  return (React.createElement(FileTreeItem, { key: logName, name: logName, isFile: true, level: 1, isSelected: activeTab === logName, exists: exists, onClick: () => {
252
314
  if (exists) {
253
315
  setActiveTab(logName);
@@ -267,15 +329,16 @@ export const TestPageView = ({ projectName, testName, decodedTestPath, runtime,
267
329
  }
268
330
  } }));
269
331
  })))),
270
- Object.values(RUNTIME_SPECIFIC_LOGS[runtime]).length > 0 && (React.createElement("div", { className: "p-2" },
332
+ runtime && RUNTIME_SPECIFIC_LOGS[runtime] &&
333
+ Object.values(RUNTIME_SPECIFIC_LOGS[runtime]).length > 0 && (React.createElement("div", { className: "p-2" },
271
334
  React.createElement("div", { className: "d-flex align-items-center text-muted mb-1", style: { cursor: 'pointer', fontSize: '0.875rem' }, onClick: () => setExpandedSections(prev => (Object.assign(Object.assign({}, prev), { runtimeLogs: !prev.runtimeLogs }))) },
272
335
  React.createElement("i", { className: `bi bi-chevron-${expandedSections.runtimeLogs ? 'down' : 'right'} me-1` }),
273
336
  React.createElement("span", null, "Runtime Logs")),
274
337
  expandedSections.runtimeLogs && (React.createElement("div", null, Object.values(RUNTIME_SPECIFIC_LOGS[runtime]).map((logName) => {
275
- const logContent = logs[logName];
338
+ const logContent = logs ? logs[logName] : undefined;
276
339
  const exists = logContent !== undefined &&
277
340
  ((typeof logContent === "string" && logContent.trim() !== "") ||
278
- (typeof logContent === "object" && Object.keys(logContent).length > 0));
341
+ (typeof logContent === "object" && logContent !== null && Object.keys(logContent).length > 0));
279
342
  return (React.createElement(FileTreeItem, { key: logName, name: logName, isFile: true, level: 1, isSelected: activeTab === logName, exists: exists, onClick: () => {
280
343
  if (exists) {
281
344
  setActiveTab(logName);
@@ -295,7 +358,7 @@ export const TestPageView = ({ projectName, testName, decodedTestPath, runtime,
295
358
  }
296
359
  } }));
297
360
  }))))),
298
- logs.source_files && (React.createElement("div", { className: "p-2" },
361
+ logs && logs.source_files && (React.createElement("div", { className: "p-2" },
299
362
  React.createElement("div", { className: "d-flex align-items-center text-muted mb-1", style: { cursor: 'pointer', fontSize: '0.875rem' }, onClick: () => setExpandedSections(prev => (Object.assign(Object.assign({}, prev), { sourceFiles: !prev.sourceFiles }))) },
300
363
  React.createElement("i", { className: `bi bi-chevron-${expandedSections.sourceFiles ? 'down' : 'right'} me-1` }),
301
364
  React.createElement("span", null, "Source Files")),
@@ -326,7 +389,59 @@ export const TestPageView = ({ projectName, testName, decodedTestPath, runtime,
326
389
  React.createElement("img", { src: selectedFile.content, alt: selectedFile.path, className: "img-fluid", style: { maxHeight: '300px' } }),
327
390
  React.createElement("div", { className: "mt-2" },
328
391
  React.createElement("a", { href: selectedFile.content, target: "_blank", rel: "noopener noreferrer", className: "btn btn-sm btn-outline-primary" }, "Open Full Size")))),
329
- (selectedFile === null || selectedFile === void 0 ? void 0 : selectedFile.path.endsWith(".json")) && !selectedFile.path.endsWith("tests.json") && (React.createElement("pre", { className: "bg-light p-2 small" },
392
+ (selectedFile === null || selectedFile === void 0 ? void 0 : selectedFile.path.endsWith("build.json")) && (React.createElement("div", null,
393
+ React.createElement("h5", null, "Build Information"),
394
+ (() => {
395
+ var _a, _b;
396
+ try {
397
+ const buildData = JSON.parse(selectedFile.content);
398
+ return (React.createElement(React.Fragment, null,
399
+ ((_a = buildData.errors) === null || _a === void 0 ? void 0 : _a.length) > 0 && (React.createElement("div", { className: "mb-3" },
400
+ React.createElement("h6", { className: "text-danger" },
401
+ "Errors (",
402
+ buildData.errors.length,
403
+ ")"),
404
+ React.createElement("ul", { className: "list-unstyled" }, buildData.errors.map((error, index) => (React.createElement("li", { key: index, className: "mb-2 p-2 bg-light rounded" },
405
+ React.createElement("div", { className: "text-danger fw-bold" }, error.text),
406
+ error.location && (React.createElement("div", { className: "small text-muted" },
407
+ "File: ",
408
+ error.location.file,
409
+ "Line: ",
410
+ error.location.line,
411
+ "Column: ",
412
+ error.location.column)),
413
+ error.notes && error.notes.length > 0 && (React.createElement("div", { className: "small" },
414
+ "Notes:",
415
+ React.createElement("ul", null, error.notes.map((note, noteIndex) => (React.createElement("li", { key: noteIndex }, note.text)))))))))))),
416
+ ((_b = buildData.warnings) === null || _b === void 0 ? void 0 : _b.length) > 0 && (React.createElement("div", { className: "mb-3" },
417
+ React.createElement("h6", { className: "text-warning" },
418
+ "Warnings (",
419
+ buildData.warnings.length,
420
+ ")"),
421
+ React.createElement("ul", { className: "list-unstyled" }, buildData.warnings.map((warning, index) => (React.createElement("li", { key: index, className: "mb-2 p-2 bg-light rounded" },
422
+ React.createElement("div", { className: "text-warning fw-bold" }, warning.text),
423
+ warning.location && (React.createElement("div", { className: "small text-muted" },
424
+ "File: ",
425
+ warning.location.file,
426
+ "Line: ",
427
+ warning.location.line,
428
+ "Column: ",
429
+ warning.location.column)),
430
+ warning.notes && warning.notes.length > 0 && (React.createElement("div", { className: "small" },
431
+ "Notes:",
432
+ React.createElement("ul", null, warning.notes.map((note, noteIndex) => (React.createElement("li", { key: noteIndex }, note.text)))))))))))),
433
+ (!buildData.errors || buildData.errors.length === 0) &&
434
+ (!buildData.warnings || buildData.warnings.length === 0) && (React.createElement("div", { className: "alert alert-success" }, "No build errors or warnings"))));
435
+ }
436
+ catch (e) {
437
+ return (React.createElement("div", { className: "alert alert-danger" },
438
+ "Error parsing build.json: ",
439
+ e.message));
440
+ }
441
+ })())),
442
+ (selectedFile === null || selectedFile === void 0 ? void 0 : selectedFile.path.endsWith(".json")) &&
443
+ !selectedFile.path.endsWith("tests.json") &&
444
+ !selectedFile.path.endsWith("build.json") && (React.createElement("pre", { className: "bg-light p-2 small" },
330
445
  React.createElement("code", null, selectedFile.content))),
331
446
  (selectedFile === null || selectedFile === void 0 ? void 0 : selectedFile.path.includes("source_files")) && (React.createElement("div", null,
332
447
  React.createElement("div", { className: "mb-2 small text-muted" },