tewip-ai 0.18.0 → 0.18.2

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.
@@ -116,6 +116,9 @@ function junitCases(root, workspace) {
116
116
  }
117
117
  out.push({ testId, file: file || (testcase.attrs.classname ?? '').trim(), duration: Number.isFinite(seconds) ? Math.round(seconds * 1000) : 0, attempts });
118
118
  };
119
+ // <testrun> is the root Eclipse's JUnit runner and Ant write; everything inside it is ordinary
120
+ // JUnit XML. A real report in that shape was rejected outright as "no test report Tewip can
121
+ // read", which is a poor answer to a file holding 36 perfectly readable results.
119
122
  walk(root, root.name === 'testsuite' ? root : undefined);
120
123
  // Attempts whose error the runner did not record borrow the final one's, when there is one.
121
124
  for (const c of out) {
@@ -193,6 +196,26 @@ export function junitFiles(path) {
193
196
  * Playwright; every test, passing or failing, is counted in the run summary so its history
194
197
  * shows the passes too.
195
198
  */
199
+ /**
200
+ * A runner's own timestamp, when it is one a machine can read.
201
+ *
202
+ * Maven Surefire writes `timestamp="2025-03-05T11:53:11 IST"` - a timezone abbreviation with no
203
+ * offset, which is not a date any parser accepts. `new Date(...).toISOString()` then threw, and
204
+ * Tewip died on one of the most widely used test runners there is. This was found by reading real
205
+ * Surefire reports from public repositories; every fixture collected for this project had a clean
206
+ * timestamp. A report Tewip cannot date is still a report worth reading, so an unreadable one falls
207
+ * back to the time of import rather than stopping everything.
208
+ */
209
+ function readTimestamp(raw) {
210
+ if (!raw)
211
+ return null;
212
+ const asIs = new Date(raw);
213
+ if (!Number.isNaN(asIs.getTime()))
214
+ return asIs.toISOString();
215
+ // Drop a trailing zone abbreviation (IST, CEST, PDT...) and read the rest as local time.
216
+ const withoutZone = new Date(raw.replace(/\s+[A-Z]{2,5}$/, ''));
217
+ return Number.isNaN(withoutZone.getTime()) ? null : withoutZone.toISOString();
218
+ }
196
219
  export function importJunit(path, meta) {
197
220
  const records = [];
198
221
  const attempts = {};
@@ -229,7 +252,7 @@ export function importJunit(path, meta) {
229
252
  if (start && (!startedAt || start < startedAt))
230
253
  startedAt = start;
231
254
  }
232
- else if (root.name === 'testsuites' || root.name === 'testsuite') {
255
+ else if (root.name === 'testsuites' || root.name === 'testsuite' || root.name === 'testrun') {
233
256
  cases = junitCases(root, meta.workspace);
234
257
  const stamp = root.attrs.timestamp ?? root.children.find((c) => c.name === 'testsuite')?.attrs.timestamp;
235
258
  if (stamp && (!startedAt || stamp < startedAt))
@@ -288,7 +311,7 @@ export function importJunit(path, meta) {
288
311
  runId: meta.runId,
289
312
  gitSha: meta.gitSha,
290
313
  ...(meta.branch ? { branch: meta.branch } : {}),
291
- startedAt: startedAt ? new Date(startedAt).toISOString() : now,
314
+ startedAt: readTimestamp(startedAt) ?? now,
292
315
  finishedAt: now,
293
316
  status: anyFailed ? 'failed' : 'passed',
294
317
  attempts,
@@ -297,7 +320,7 @@ export function importJunit(path, meta) {
297
320
  if (unread.length > 0) {
298
321
  const list = unread.slice(0, 5).join(', ');
299
322
  if (parsedFiles === 0) {
300
- throw new Error(`no test report Tewip can read in ${path}: ${list}. It reads JUnit XML (<testsuites>/<testsuite>), NUnit 3 (<test-run>), .NET TRX (<TestRun>), ` +
323
+ throw new Error(`no test report Tewip can read in ${path}: ${list}. It reads JUnit XML (<testsuites>/<testsuite>/<testrun>), NUnit 3 (<test-run>), .NET TRX (<TestRun>), ` +
301
324
  'Robot Framework output.xml (<robot>), JMeter .jtl (<testResults>) and a k6 summary (--summary-export). ' +
302
325
  'Most runners can write JUnit XML; for TestNG use the Surefire report, and for NUnit use --result=x.xml.');
303
326
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tewip-ai",
3
- "version": "0.18.0",
3
+ "version": "0.18.2",
4
4
  "description": "Tewip finds why each failing test failed - real bug, flaky test, environment, test data or changed selector - for any stack, from the command line, CI, or your editor.",
5
5
  "keywords": [
6
6
  "test-failures",