@test-station/render-html 0.2.22 → 0.2.23

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +62 -9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@test-station/render-html",
3
- "version": "0.2.22",
3
+ "version": "0.2.23",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
package/src/index.js CHANGED
@@ -1156,14 +1156,18 @@ function renderModuleCard(moduleEntry) {
1156
1156
  }
1157
1157
 
1158
1158
  function renderPackageCard(pkg) {
1159
- const status = pkg.status || deriveStatusFromSummary(pkg.summary);
1159
+ const status = deriveDisplayStatus({
1160
+ summary: pkg.summary,
1161
+ reportedStatus: pkg.status,
1162
+ suites: pkg.suites,
1163
+ });
1160
1164
  const targetId = `package-${slugify(pkg.name)}`;
1161
1165
  const filterAttrs = renderFilterAttributes({
1162
1166
  nodeType: 'package-card',
1163
1167
  moduleNames: pkg.modules,
1164
1168
  packageNames: [pkg.name],
1165
1169
  frameworks: pkg.frameworks,
1166
- hasFailures: (pkg.summary?.failed || 0) > 0,
1170
+ hasFailures: status === 'failed' || (pkg.summary?.failed || 0) > 0,
1167
1171
  lineCoverage: pkg.coverage?.lines?.pct,
1168
1172
  });
1169
1173
  return `
@@ -1224,7 +1228,11 @@ function renderModuleSection(moduleEntry, rootDir) {
1224
1228
  }
1225
1229
 
1226
1230
  function renderPackageSection(pkg, rootDir) {
1227
- const status = pkg.status || deriveStatusFromSummary(pkg.summary);
1231
+ const status = deriveDisplayStatus({
1232
+ summary: pkg.summary,
1233
+ reportedStatus: pkg.status,
1234
+ suites: pkg.suites,
1235
+ });
1228
1236
  const suites = Array.isArray(pkg.suites) ? pkg.suites : [];
1229
1237
  const suiteMarkup = suites.length === 0
1230
1238
  ? '<div class="suite"><div class="suite__summaryRow"><div><span class="suite__label">No test suites</span></div><div class="suite__summary">No package test script was found.</div></div></div>'
@@ -1234,7 +1242,7 @@ function renderPackageSection(pkg, rootDir) {
1234
1242
  moduleNames: pkg.modules,
1235
1243
  packageNames: [pkg.name],
1236
1244
  frameworks: pkg.frameworks,
1237
- hasFailures: (pkg.summary?.failed || 0) > 0,
1245
+ hasFailures: status === 'failed' || (pkg.summary?.failed || 0) > 0,
1238
1246
  lineCoverage: pkg.coverage?.lines?.pct,
1239
1247
  });
1240
1248
  return `
@@ -1292,7 +1300,11 @@ function renderThemeSection(moduleEntry, themeEntry, rootDir) {
1292
1300
  }
1293
1301
 
1294
1302
  function renderThemePackageSection(moduleEntry, themeEntry, packageEntry, rootDir) {
1295
- const status = deriveStatusFromSummary(packageEntry.summary);
1303
+ const status = deriveDisplayStatus({
1304
+ summary: packageEntry.summary,
1305
+ reportedStatus: packageEntry.status,
1306
+ suites: packageEntry.suites,
1307
+ });
1296
1308
  const suites = Array.isArray(packageEntry.suites) ? packageEntry.suites : [];
1297
1309
  const suiteMarkup = suites.length === 0
1298
1310
  ? '<div class="suite"><div class="suite__summaryRow"><div><span class="suite__label">No test suites</span></div><div class="suite__summary">No suite results were grouped under this package.</div></div></div>'
@@ -1302,7 +1314,7 @@ function renderThemePackageSection(moduleEntry, themeEntry, packageEntry, rootDi
1302
1314
  moduleNames: [moduleEntry.module],
1303
1315
  packageNames: [packageEntry.name],
1304
1316
  frameworks: packageEntry.frameworks,
1305
- hasFailures: (packageEntry.summary?.failed || 0) > 0,
1317
+ hasFailures: status === 'failed' || (packageEntry.summary?.failed || 0) > 0,
1306
1318
  });
1307
1319
  return `
1308
1320
  <details class="package-group" ${filterAttrs}>
@@ -1321,6 +1333,10 @@ function renderThemePackageSection(moduleEntry, themeEntry, packageEntry, rootDi
1321
1333
  }
1322
1334
 
1323
1335
  function renderSuite(suite, rootDir, filterContext = {}) {
1336
+ const status = deriveDisplayStatus({
1337
+ summary: suite.summary,
1338
+ reportedStatus: suite.status,
1339
+ });
1324
1340
  const warnings = Array.isArray(suite.warnings) ? suite.warnings : [];
1325
1341
  const tests = Array.isArray(suite.tests) ? suite.tests : [];
1326
1342
  const rawArtifacts = Array.isArray(suite.rawArtifacts) ? suite.rawArtifacts : [];
@@ -1331,14 +1347,14 @@ function renderSuite(suite, rootDir, filterContext = {}) {
1331
1347
  const diagnosticsMarkup = renderDiagnosticsBlock(suite.diagnostics);
1332
1348
  const artifactMarkup = rawArtifacts.length > 0 ? renderRawArtifactBlock(rawArtifacts) : '';
1333
1349
  const testsMarkup = tests.length === 0
1334
- ? '<div class="test-row"><div class="test-row__summary"><span class="status-pill skip">skip</span><div class="test-row__name"><span class="test-row__title">No test results emitted</span></div></div></div>'
1350
+ ? renderSuiteEmptyState(status)
1335
1351
  : tests.map((test) => renderTest(suite, test, rootDir, filterContext)).join('');
1336
1352
  const filterAttrs = renderFilterAttributes({
1337
1353
  nodeType: 'suite',
1338
1354
  moduleNames: filterContext.moduleNames || dedupe(tests.map((test) => test.module || 'uncategorized')),
1339
1355
  packageNames: filterContext.packageNames || [],
1340
1356
  frameworks: [suite.runtime],
1341
- hasFailures: (suite.summary?.failed || 0) > 0,
1357
+ hasFailures: status === 'failed' || (suite.summary?.failed || 0) > 0,
1342
1358
  lineCoverage: suite.coverage?.lines?.pct,
1343
1359
  });
1344
1360
  return `
@@ -1348,7 +1364,7 @@ function renderSuite(suite, rootDir, filterContext = {}) {
1348
1364
  <div class="suite__label">${escapeHtml(suite.label)}</div>
1349
1365
  <div class="suite__runtime">${escapeHtml(suite.runtime || 'custom')} • ${escapeHtml(suite.command || '')}</div>
1350
1366
  </div>
1351
- <div class="suite__summary">${escapeHtml(formatSummary(suite.summary))} • ${escapeHtml(formatDuration(suite.durationMs || 0))}</div>
1367
+ <div class="suite__summary">${renderStatusPill(status)} <span>${escapeHtml(formatSummary(suite.summary))} • ${escapeHtml(formatDuration(suite.durationMs || 0))}</span></div>
1352
1368
  </summary>
1353
1369
  <div class="suite__body">
1354
1370
  ${warningMarkup}
@@ -1361,6 +1377,17 @@ function renderSuite(suite, rootDir, filterContext = {}) {
1361
1377
  `;
1362
1378
  }
1363
1379
 
1380
+ function renderSuiteEmptyState(status) {
1381
+ const statusClass = status === 'failed' ? 'fail' : status === 'passed' ? 'pass' : 'skip';
1382
+ const title = status === 'failed'
1383
+ ? 'Suite failed before emitting test results'
1384
+ : status === 'passed'
1385
+ ? 'Suite passed without discrete test records'
1386
+ : 'No test results emitted';
1387
+
1388
+ return `<div class="test-row"><div class="test-row__summary"><span class="status-pill ${statusClass}">${escapeHtml(status)}</span><div class="test-row__name"><span class="test-row__title">${escapeHtml(title)}</span></div></div></div>`;
1389
+ }
1390
+
1364
1391
  function renderRawArtifactBlock(rawArtifacts) {
1365
1392
  return `
1366
1393
  <section class="suite__artifacts">
@@ -1392,6 +1419,25 @@ function capitalize(value) {
1392
1419
  return normalized.length > 0 ? normalized[0].toUpperCase() + normalized.slice(1) : normalized;
1393
1420
  }
1394
1421
 
1422
+ function deriveDisplayStatus({ summary, reportedStatus = null, suites = [] } = {}) {
1423
+ const normalizedReportedStatus = normalizeOptionalStatus(reportedStatus);
1424
+ const suiteStatuses = (Array.isArray(suites) ? suites : []).map((suite) => normalizeOptionalStatus(suite?.status));
1425
+
1426
+ if (suiteStatuses.includes('failed') || normalizedReportedStatus === 'failed') {
1427
+ return 'failed';
1428
+ }
1429
+
1430
+ if (summary && summary.total > 0) {
1431
+ return deriveStatusFromSummary(summary);
1432
+ }
1433
+
1434
+ if (suiteStatuses.includes('passed') || normalizedReportedStatus === 'passed') {
1435
+ return 'passed';
1436
+ }
1437
+
1438
+ return 'skipped';
1439
+ }
1440
+
1395
1441
  function renderTest(suite, test, rootDir, filterContext = {}) {
1396
1442
  const statusClass = test.status === 'failed' ? 'fail' : test.status === 'skipped' ? 'skip' : 'pass';
1397
1443
  const assertions = Array.isArray(test.assertions) && test.assertions.length > 0
@@ -1592,6 +1638,13 @@ function deriveStatusFromSummary(summary) {
1592
1638
  return 'passed';
1593
1639
  }
1594
1640
 
1641
+ function normalizeOptionalStatus(status) {
1642
+ if (status === 'failed' || status === 'skipped' || status === 'passed') {
1643
+ return status;
1644
+ }
1645
+ return null;
1646
+ }
1647
+
1595
1648
  function formatSummary(summary = {}) {
1596
1649
  const total = Number.isFinite(summary.total) ? summary.total : 0;
1597
1650
  const passed = Number.isFinite(summary.passed) ? summary.passed : 0;