@arghajit/dummy 0.1.0-beta-5 → 0.1.0-beta-7

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.
@@ -87,13 +87,14 @@ class PlaywrightPulseReporter {
87
87
  : configDir;
88
88
  this.outputDir = path.resolve(configFileDir, (_a = this.options.outputDir) !== null && _a !== void 0 ? _a : "pulse-report");
89
89
  this.attachmentsDir = path.resolve(this.outputDir, ATTACHMENTS_SUBDIR);
90
- this.options.outputDir = this.outputDir;
90
+ this.options.outputDir = this.outputDir; // Ensure options has the resolved path
91
91
  const totalShards = this.config.shard ? this.config.shard.total : 1;
92
92
  this.isSharded = totalShards > 1;
93
93
  this.shardIndex = this.config.shard
94
94
  ? this.config.shard.current - 1
95
95
  : undefined;
96
96
  this._ensureDirExists(this.outputDir)
97
+ .then(() => this._ensureDirExists(this.attachmentsDir)) // Also ensure attachmentsDir exists
97
98
  .then(() => {
98
99
  if (this.shardIndex === undefined || this.shardIndex === 0) {
99
100
  console.log(`PlaywrightPulseReporter: Starting test run with ${suite.allTests().length} tests${this.isSharded ? ` across ${totalShards} shards` : ""}. Pulse outputting to ${this.outputDir}`);
@@ -106,10 +107,11 @@ class PlaywrightPulseReporter {
106
107
  .catch((err) => console.error("Pulse Reporter: Error during initialization:", err));
107
108
  }
108
109
  onTestBegin(test) {
109
- // console.log(`Starting test: ${test.title}`);
110
+ // Optional: console.log(`Starting test: ${test.titlePath().join(' > ')} for project ${test.parent?.project()?.name}`);
110
111
  }
111
- async processStep(step, testId, browserName, testCase) {
112
- var _a, _b, _c, _d;
112
+ async processStep(step, testId, browserName, // This will be the detailed browser info string
113
+ testCase) {
114
+ var _a, _b, _c, _d, _e;
113
115
  let stepStatus = "passed";
114
116
  let errorMessage = ((_a = step.error) === null || _a === void 0 ? void 0 : _a.message) || undefined;
115
117
  if ((_c = (_b = step.error) === null || _b === void 0 ? void 0 : _b.message) === null || _c === void 0 ? void 0 : _c.startsWith("Test is skipped:")) {
@@ -122,7 +124,8 @@ class PlaywrightPulseReporter {
122
124
  const startTime = new Date(step.startTime);
123
125
  const endTime = new Date(startTime.getTime() + Math.max(0, duration));
124
126
  let codeLocation = "";
125
- if (step.location) {
127
+ if ((_d = step.location) === null || _d === void 0 ? void 0 : _d.file) {
128
+ // Check if file path exists
126
129
  codeLocation = `${path.relative(this.config.rootDir, step.location.file)}:${step.location.line}:${step.location.column}`;
127
130
  }
128
131
  let stepTitle = step.title;
@@ -133,9 +136,9 @@ class PlaywrightPulseReporter {
133
136
  duration: duration,
134
137
  startTime: startTime,
135
138
  endTime: endTime,
136
- browser: browserName,
139
+ browser: browserName, // Store the detailed browser string for the step
137
140
  errorMessage: errorMessage,
138
- stackTrace: ((_d = step.error) === null || _d === void 0 ? void 0 : _d.stack) || undefined,
141
+ stackTrace: ((_e = step.error) === null || _e === void 0 ? void 0 : _e.stack) || undefined,
139
142
  codeLocation: codeLocation || undefined,
140
143
  isHook: step.category === "hook",
141
144
  hookType: step.category === "hook"
@@ -143,120 +146,107 @@ class PlaywrightPulseReporter {
143
146
  ? "before"
144
147
  : "after"
145
148
  : undefined,
146
- steps: [],
149
+ steps: [], // Will be populated by recursive calls in onTestEnd
147
150
  };
148
151
  }
149
152
  getBrowserInfo(test) {
150
- var _a, _b, _c, _d, _e, _f, _g, _h;
151
- // Changed return type to string
153
+ var _a, _b, _c;
152
154
  const project = (_a = test.parent) === null || _a === void 0 ? void 0 : _a.project();
153
- const configuredBrowserType = (_c = (_b = project === null || project === void 0 ? void 0 : project.use) === null || _b === void 0 ? void 0 : _b.defaultBrowserType) === null || _c === void 0 ? void 0 : _c.toLowerCase(); // e.g., "chromium", "firefox", "webkit"
154
- const userAgentString = (_d = project === null || project === void 0 ? void 0 : project.use) === null || _d === void 0 ? void 0 : _d.userAgent;
155
- let finalBrowserName = configuredBrowserType || "unknown"; // Start with the configured type or "unknown"
156
- let version = "";
157
- let osName = "";
158
- let osVersion = "";
159
- let deviceType = "";
155
+ const configuredBrowserType = (_c = (_b = project === null || project === void 0 ? void 0 : project.use) === null || _b === void 0 ? void 0 : _b.defaultBrowserType) === null || _c === void 0 ? void 0 : _c.toLowerCase();
156
+ const userAgentString = test.info().project.use.userAgent;
157
+ // --- DEBUG LOGS (IMPORTANT! Check these in your console output) ---
158
+ console.log(`[PulseReporter DEBUG] Project: ${(project === null || project === void 0 ? void 0 : project.name) || "N/A"}`);
159
+ console.log(`[PulseReporter DEBUG] Configured Browser Type: "${configuredBrowserType}"`);
160
+ console.log(`[PulseReporter DEBUG] User Agent String for UAParser: "${userAgentString}"`);
161
+ // --- END DEBUG LOGS ---
162
+ let parsedBrowserName;
163
+ let parsedVersion;
164
+ let parsedOsName;
165
+ let parsedOsVersion;
166
+ let deviceModel;
167
+ let deviceType;
160
168
  if (userAgentString) {
161
169
  try {
162
170
  const parser = new ua_parser_js_1.UAParser(userAgentString);
163
171
  const uaResult = parser.getResult();
164
- deviceType = uaResult.device.type || ""; // e.g., "mobile", "tablet", "console", "smarttv"
165
- // 1. Try UAParser's browser name
166
- if (uaResult.browser.name) {
167
- finalBrowserName = uaResult.browser.name;
168
- if (uaResult.browser.version) {
169
- // Get major version, or full version if no dot
170
- version = ` v${uaResult.browser.version.split(".")[0]}`;
171
- }
172
- }
173
- // If UAParser didn't find a browser name, but we have an engine,
174
- // it might be more informative than just the configuredBrowserType.
175
- else if (uaResult.engine.name &&
176
- configuredBrowserType !== uaResult.engine.name.toLowerCase()) {
177
- // Prefer engine name if it's more specific and different from default (e.g. WebKit for a generic device)
178
- finalBrowserName = uaResult.engine.name;
179
- }
180
- // 2. Specific Overrides / Refinements
181
- // Handling for mobile devices, especially if UAParser provides generic browser names
172
+ // --- DEBUG LOGS (IMPORTANT! Check these in your console output) ---
173
+ console.log("[PulseReporter DEBUG] UAParser Result:", JSON.stringify(uaResult, null, 2));
174
+ // --- END DEBUG LOGS ---
175
+ parsedBrowserName = uaResult.browser.name;
176
+ parsedVersion = uaResult.browser.version;
177
+ parsedOsName = uaResult.os.name;
178
+ parsedOsVersion = uaResult.os.version;
179
+ deviceModel = uaResult.device.model;
180
+ deviceType = uaResult.device.type;
182
181
  if (deviceType === "mobile" || deviceType === "tablet") {
183
- if (((_e = uaResult.os.name) === null || _e === void 0 ? void 0 : _e.toLowerCase().includes("ios")) ||
184
- uaResult.browser.name === "Mobile Safari") {
185
- finalBrowserName = "Mobile Safari";
186
- }
187
- else if ((_f = uaResult.os.name) === null || _f === void 0 ? void 0 : _f.toLowerCase().includes("android")) {
188
- if ((_g = uaResult.browser.name) === null || _g === void 0 ? void 0 : _g.toLowerCase().includes("chrome")) {
189
- finalBrowserName = "Chrome Mobile";
182
+ if (parsedOsName === null || parsedOsName === void 0 ? void 0 : parsedOsName.toLowerCase().includes("android")) {
183
+ if (parsedBrowserName === null || parsedBrowserName === void 0 ? void 0 : parsedBrowserName.toLowerCase().includes("chrome")) {
184
+ parsedBrowserName = "Chrome Mobile";
190
185
  }
191
- else if ((_h = uaResult.browser.name) === null || _h === void 0 ? void 0 : _h.toLowerCase().includes("firefox")) {
192
- finalBrowserName = "Firefox Mobile";
186
+ else if (parsedBrowserName === null || parsedBrowserName === void 0 ? void 0 : parsedBrowserName.toLowerCase().includes("firefox")) {
187
+ parsedBrowserName = "Firefox Mobile";
193
188
  }
194
- else if (uaResult.engine.name === "Blink" &&
195
- !uaResult.browser.name) {
196
- // Generic Android Webview
197
- finalBrowserName = "Android WebView";
189
+ else if (uaResult.engine.name === "Blink" && !parsedBrowserName) {
190
+ parsedBrowserName = "Android WebView";
198
191
  }
199
- else if (uaResult.browser.name) {
200
- finalBrowserName = `${uaResult.browser.name} Mobile`; // Generic, e.g., "Opera Mobile"
192
+ else if (parsedBrowserName) {
193
+ // Parsed name is likely okay
201
194
  }
202
195
  else {
203
- finalBrowserName = "Android Browser"; // Fallback for Android
196
+ parsedBrowserName = "Android Browser";
204
197
  }
205
198
  }
206
- }
207
- else if (uaResult.browser.name === "Electron") {
208
- finalBrowserName = "Electron App"; // More descriptive for Electron
209
- // For Electron, version might be app's version, not Chromium's.
210
- // You might need custom logic if you want the underlying Chromium version.
211
- }
212
- // 3. OS Information
213
- if (uaResult.os.name) {
214
- osName = ` on ${uaResult.os.name}`;
215
- if (uaResult.os.version) {
216
- osVersion = ` ${uaResult.os.version.split(".")[0]}`; // Major OS version
199
+ else if (parsedOsName === null || parsedOsName === void 0 ? void 0 : parsedOsName.toLowerCase().includes("ios")) {
200
+ parsedBrowserName = "Mobile Safari";
217
201
  }
218
202
  }
203
+ else if (parsedBrowserName === "Electron") {
204
+ parsedBrowserName = "Electron App";
205
+ }
219
206
  }
220
207
  catch (error) {
221
208
  console.warn(`Pulse Reporter: Error parsing User-Agent string "${userAgentString}":`, error);
222
- // Fallback to configuredBrowserType already set in finalBrowserName
223
209
  }
224
210
  }
225
- // If after UA parsing, we still have a generic engine name like "Blink" or "WebKit"
226
- // and a more specific configuredBrowserType exists (like "chromium"), prefer the configured one.
227
- if ((finalBrowserName.toLowerCase() === "blink" ||
228
- finalBrowserName.toLowerCase() === "webkit" ||
229
- finalBrowserName.toLowerCase() === "gecko") &&
230
- configuredBrowserType &&
231
- configuredBrowserType !== "unknown") {
232
- finalBrowserName =
211
+ let finalDisplayName;
212
+ if (parsedBrowserName) {
213
+ finalDisplayName = parsedBrowserName;
214
+ if (parsedVersion) {
215
+ finalDisplayName += ` v${parsedVersion.split(".")[0]}`;
216
+ }
217
+ }
218
+ else if (configuredBrowserType && configuredBrowserType !== "unknown") {
219
+ finalDisplayName =
233
220
  configuredBrowserType.charAt(0).toUpperCase() +
234
- configuredBrowserType.slice(1); // Capitalize
235
- }
236
- // Construct the display string
237
- // Prioritize showing device type for mobile/tablet if it adds clarity
238
- let displayString = finalBrowserName;
239
- if (version)
240
- displayString += version;
241
- // Add device type if it's mobile/tablet and not already obvious from browser name
242
- if ((deviceType === "mobile" || deviceType === "tablet") &&
243
- !finalBrowserName.toLowerCase().includes(deviceType)) {
244
- // displayString += ` (${deviceType.charAt(0).toUpperCase() + deviceType.slice(1)})`;
245
- }
246
- if (osName)
247
- displayString += osName;
248
- if (osVersion && osName)
249
- displayString += osVersion; // Only add osVersion if osName is present
250
- return displayString.trim();
221
+ configuredBrowserType.slice(1);
222
+ }
223
+ else {
224
+ finalDisplayName = "Unknown Browser";
225
+ }
226
+ if (parsedOsName) {
227
+ finalDisplayName += ` on ${parsedOsName}`;
228
+ if (parsedOsVersion) {
229
+ finalDisplayName += ` ${parsedOsVersion.split(".")[0]}`;
230
+ }
231
+ }
232
+ // Example: Append device model if it's a mobile/tablet and model exists
233
+ // if ((deviceType === "mobile" || deviceType === "tablet") && deviceModel && !finalDisplayName.includes(deviceModel)) {
234
+ // finalDisplayName += ` (${deviceModel})`;
235
+ // }
236
+ return finalDisplayName.trim();
251
237
  }
252
238
  async onTestEnd(test, result) {
253
- var _a, _b, _c, _d, _e, _f, _g, _h;
239
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
254
240
  const project = (_a = test.parent) === null || _a === void 0 ? void 0 : _a.project();
255
- const browserDisplayInfo = this.getBrowserInfo(test);
241
+ // const browserDisplayInfo = this.getBrowserInfo(test);
242
+ const ua = test.info().project.use.userAgent;
243
+ const parser = new ua_parser_js_1.UAParser(ua);
244
+ const res = parser.getResult();
245
+ const browserDisplayInfo = res.browser.name || "";
256
246
  const testStatus = convertStatus(result.status, test);
257
247
  const startTime = new Date(result.startTime);
258
248
  const endTime = new Date(startTime.getTime() + result.duration);
259
- const testIdForFiles = test.id ||
249
+ const testIdForFiles = test.id || // Playwright's internal unique ID for the test case
260
250
  `${test
261
251
  .titlePath()
262
252
  .join("_")
@@ -264,60 +254,54 @@ class PlaywrightPulseReporter {
264
254
  const processAllSteps = async (steps) => {
265
255
  let processed = [];
266
256
  for (const step of steps) {
267
- const processedStep = await this.processStep(step, testIdForFiles, browserDisplayInfo, test);
257
+ const processedStep = await this.processStep(step, testIdForFiles, browserDisplayInfo, // Pass the detailed browser info string
258
+ test);
268
259
  processed.push(processedStep);
269
260
  if (step.steps && step.steps.length > 0) {
270
- processedStep.steps = await processAllSteps(step.steps);
261
+ processedStep.steps = await processAllSteps(step.steps); // Recursive call
271
262
  }
272
263
  }
273
264
  return processed;
274
265
  };
275
266
  let codeSnippet = undefined;
276
267
  try {
277
- if (((_b = test.location) === null || _b === void 0 ? void 0 : _b.file) && ((_c = test.location) === null || _c === void 0 ? void 0 : _c.line) && ((_d = test.location) === null || _d === void 0 ? void 0 : _d.column)) {
268
+ if (((_b = test.location) === null || _b === void 0 ? void 0 : _b.file) &&
269
+ ((_c = test.location) === null || _c === void 0 ? void 0 : _c.line) !== undefined &&
270
+ ((_d = test.location) === null || _d === void 0 ? void 0 : _d.column) !== undefined) {
278
271
  const relativePath = path.relative(this.config.rootDir, test.location.file);
279
272
  codeSnippet = `Test defined at: ${relativePath}:${test.location.line}:${test.location.column}`;
280
273
  }
281
274
  }
282
275
  catch (e) {
283
- console.warn(`Pulse Reporter: Could not extract code snippet for ${test.title}`, e);
284
- }
285
- const stdoutMessages = [];
286
- if (result.stdout && result.stdout.length > 0) {
287
- result.stdout.forEach((item) => {
288
- stdoutMessages.push(typeof item === "string" ? item : item.toString());
289
- });
276
+ // console.warn(`Pulse Reporter: Could not extract code snippet for ${test.title}`, e);
290
277
  }
291
- const stderrMessages = [];
292
- if (result.stderr && result.stderr.length > 0) {
293
- result.stderr.forEach((item) => {
294
- stderrMessages.push(typeof item === "string" ? item : item.toString());
295
- });
296
- }
297
- const uniqueTestId = test.id;
278
+ const stdoutMessages = ((_e = result.stdout) === null || _e === void 0 ? void 0 : _e.map((item) => typeof item === "string" ? item : item.toString())) || [];
279
+ const stderrMessages = ((_f = result.stderr) === null || _f === void 0 ? void 0 : _f.map((item) => typeof item === "string" ? item : item.toString())) || [];
280
+ const uniqueTestId = test.id; // test.id is Playwright's unique ID for a test case instance
298
281
  const pulseResult = {
299
282
  id: uniqueTestId,
300
- runId: "TBD",
283
+ runId: "TBD", // Will be set during final report generation
301
284
  name: test.titlePath().join(" > "),
302
- suiteName: (project === null || project === void 0 ? void 0 : project.name) || ((_e = this.config.projects[0]) === null || _e === void 0 ? void 0 : _e.name) || "Default Suite",
285
+ suiteName: (project === null || project === void 0 ? void 0 : project.name) || ((_g = this.config.projects[0]) === null || _g === void 0 ? void 0 : _g.name) || "Default Suite",
303
286
  status: testStatus,
304
287
  duration: result.duration,
305
288
  startTime: startTime,
306
289
  endTime: endTime,
307
- browser: browserDisplayInfo,
290
+ browser: browserDisplayInfo, // Use the detailed browser string
308
291
  retries: result.retry,
309
- steps: ((_f = result.steps) === null || _f === void 0 ? void 0 : _f.length) ? await processAllSteps(result.steps) : [],
310
- errorMessage: (_g = result.error) === null || _g === void 0 ? void 0 : _g.message,
311
- stackTrace: (_h = result.error) === null || _h === void 0 ? void 0 : _h.stack,
292
+ steps: ((_h = result.steps) === null || _h === void 0 ? void 0 : _h.length) ? await processAllSteps(result.steps) : [],
293
+ errorMessage: (_j = result.error) === null || _j === void 0 ? void 0 : _j.message,
294
+ stackTrace: (_k = result.error) === null || _k === void 0 ? void 0 : _k.stack,
312
295
  codeSnippet: codeSnippet,
313
296
  tags: test.tags.map((tag) => tag.startsWith("@") ? tag.substring(1) : tag),
314
- screenshots: [],
315
- videoPath: undefined,
316
- tracePath: undefined,
297
+ screenshots: [], // To be populated by attachFiles
298
+ videoPath: undefined, // To be populated by attachFiles
299
+ tracePath: undefined, // To be populated by attachFiles
317
300
  stdout: stdoutMessages.length > 0 ? stdoutMessages : undefined,
318
301
  stderr: stderrMessages.length > 0 ? stderrMessages : undefined,
319
302
  };
320
303
  try {
304
+ // IMPORTANT: attachFiles logic
321
305
  (0, attachment_utils_1.attachFiles)(testIdForFiles, result, pulseResult, this.options);
322
306
  }
323
307
  catch (attachError) {
@@ -352,27 +336,28 @@ class PlaywrightPulseReporter {
352
336
  console.error(`Pulse Reporter: Shard ${this.shardIndex} failed to write temporary results to ${tempFilePath}`, error);
353
337
  }
354
338
  }
355
- async _mergeShardResults(finalRunData) {
339
+ async _mergeShardResults(finalRunData // Pass the TestRun object to populate
340
+ ) {
341
+ var _a, _b;
356
342
  let allShardProcessedResults = [];
357
- const totalShards = this.config.shard ? this.config.shard.total : 1;
343
+ const totalShards = (_b = (_a = this.config.shard) === null || _a === void 0 ? void 0 : _a.total) !== null && _b !== void 0 ? _b : 1;
358
344
  for (let i = 0; i < totalShards; i++) {
359
345
  const tempFilePath = path.join(this.outputDir, `${TEMP_SHARD_FILE_PREFIX}${i}.json`);
360
346
  try {
361
347
  const content = await fs.readFile(tempFilePath, "utf-8");
362
- const shardResults = JSON.parse(content);
363
- allShardProcessedResults =
364
- allShardProcessedResults.concat(shardResults);
348
+ const shardResults = JSON.parse(content); // Dates are already ISO strings
349
+ allShardProcessedResults.push(...shardResults);
365
350
  }
366
351
  catch (error) {
367
352
  if ((error === null || error === void 0 ? void 0 : error.code) === "ENOENT") {
368
- console.warn(`Pulse Reporter: Shard results file not found: ${tempFilePath}. This might be normal if a shard had no tests or failed early.`);
353
+ // console.warn(`Pulse Reporter: Shard results file not found: ${tempFilePath}.`);
369
354
  }
370
355
  else {
371
356
  console.error(`Pulse Reporter: Could not read/parse results from shard ${i} (${tempFilePath}). Error:`, error);
372
357
  }
373
358
  }
374
359
  }
375
- let finalUniqueResultsMap = new Map();
360
+ const finalUniqueResultsMap = new Map();
376
361
  for (const result of allShardProcessedResults) {
377
362
  const existing = finalUniqueResultsMap.get(result.id);
378
363
  if (!existing || result.retries >= existing.retries) {
@@ -380,23 +365,15 @@ class PlaywrightPulseReporter {
380
365
  }
381
366
  }
382
367
  const finalResultsList = Array.from(finalUniqueResultsMap.values());
383
- finalResultsList.forEach((r) => (r.runId = finalRunData.id));
368
+ finalResultsList.forEach((r) => (r.runId = finalRunData.id)); // Assign runId to each test result
369
+ // Update the passed finalRunData object with aggregated stats
384
370
  finalRunData.passed = finalResultsList.filter((r) => r.status === "passed").length;
385
371
  finalRunData.failed = finalResultsList.filter((r) => r.status === "failed").length;
386
372
  finalRunData.skipped = finalResultsList.filter((r) => r.status === "skipped").length;
387
373
  finalRunData.totalTests = finalResultsList.length;
388
- const reviveDates = (key, value) => {
389
- const isoDateRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z$/;
390
- if (typeof value === "string" && isoDateRegex.test(value)) {
391
- const date = new Date(value);
392
- return !isNaN(date.getTime()) ? date : value;
393
- }
394
- return value;
395
- };
396
- const properlyTypedResults = JSON.parse(JSON.stringify(finalResultsList), reviveDates);
397
374
  return {
398
- run: finalRunData,
399
- results: properlyTypedResults,
375
+ run: finalRunData, // Contains Date object for timestamp
376
+ results: finalResultsList, // Contains ISO strings for dates from shards
400
377
  metadata: { generatedAt: new Date().toISOString() },
401
378
  };
402
379
  }
@@ -410,7 +387,7 @@ class PlaywrightPulseReporter {
410
387
  }
411
388
  catch (error) {
412
389
  if ((error === null || error === void 0 ? void 0 : error.code) !== "ENOENT") {
413
- console.warn("Pulse Reporter: Warning during cleanup of temporary files:", error.message);
390
+ // console.warn("Pulse Reporter: Warning during cleanup of temporary files:", error.message);
414
391
  }
415
392
  }
416
393
  }
@@ -426,7 +403,7 @@ class PlaywrightPulseReporter {
426
403
  }
427
404
  }
428
405
  async onEnd(result) {
429
- var _a, _b, _c;
406
+ var _a, _b;
430
407
  if (this.shardIndex !== undefined) {
431
408
  await this._writeShardResults();
432
409
  return;
@@ -435,16 +412,18 @@ class PlaywrightPulseReporter {
435
412
  const duration = runEndTime - this.runStartTime;
436
413
  const runId = `run-${this.runStartTime}-${(0, crypto_1.randomUUID)()}`;
437
414
  const runData = {
415
+ // This is the single source of truth for current run's data
438
416
  id: runId,
439
- timestamp: new Date(this.runStartTime),
417
+ timestamp: new Date(this.runStartTime), // Stored as Date object
440
418
  totalTests: 0,
441
419
  passed: 0,
442
420
  failed: 0,
443
421
  skipped: 0,
444
422
  duration,
445
423
  };
446
- let finalReport = undefined; // Initialize as undefined
424
+ let finalReport;
447
425
  if (this.isSharded) {
426
+ // _mergeShardResults will populate the runData object passed to it
448
427
  finalReport = await this._mergeShardResults(runData);
449
428
  }
450
429
  else {
@@ -453,37 +432,18 @@ class PlaywrightPulseReporter {
453
432
  runData.failed = this.results.filter((r) => r.status === "failed").length;
454
433
  runData.skipped = this.results.filter((r) => r.status === "skipped").length;
455
434
  runData.totalTests = this.results.length;
456
- const reviveDates = (key, value) => {
457
- const isoDateRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z$/;
458
- if (typeof value === "string" && isoDateRegex.test(value)) {
459
- const date = new Date(value);
460
- return !isNaN(date.getTime()) ? date : value;
461
- }
462
- return value;
463
- };
464
- const properlyTypedResults = JSON.parse(JSON.stringify(this.results), reviveDates);
465
435
  finalReport = {
466
- run: runData,
467
- results: properlyTypedResults,
436
+ run: runData, // runData contains a Date object for timestamp
437
+ results: this.results, // results contain Date objects for startTime, endTime
468
438
  metadata: { generatedAt: new Date().toISOString() },
469
439
  };
470
440
  }
471
- if (!finalReport) {
472
- console.error("PlaywrightPulseReporter: CRITICAL - finalReport object was not generated. Cannot create summary.");
473
- const errorSummary = `
474
- PlaywrightPulseReporter: Run Finished
475
- -----------------------------------------
476
- Overall Status: ERROR (Report data missing)
477
- Total Tests: N/A
478
- Passed: N/A
479
- Failed: N/A
480
- Skipped: N/A
481
- Duration: N/A
482
- -----------------------------------------`;
483
- if (this.printsToStdio()) {
484
- console.log(errorSummary);
485
- }
486
- const errorReport = {
441
+ // This check should be robust now
442
+ if (!finalReport ||
443
+ !finalReport.run ||
444
+ typeof finalReport.run.totalTests !== "number") {
445
+ console.error("PlaywrightPulseReporter: CRITICAL - finalReport object or its run data was malformed. Cannot create summary.");
446
+ const errorReportMinimal = {
487
447
  run: {
488
448
  id: runId,
489
449
  timestamp: new Date(this.runStartTime),
@@ -491,28 +451,30 @@ PlaywrightPulseReporter: Run Finished
491
451
  passed: 0,
492
452
  failed: 0,
493
453
  skipped: 0,
494
- duration: duration,
454
+ duration,
495
455
  },
496
456
  results: [],
497
457
  metadata: {
498
458
  generatedAt: new Date().toISOString(),
499
459
  },
500
460
  };
501
- const finalOutputPathOnError = path.join(this.outputDir, this.baseOutputFile);
502
461
  try {
462
+ const errorPath = path.join(this.outputDir, this.baseOutputFile);
503
463
  await this._ensureDirExists(this.outputDir);
504
- await fs.writeFile(finalOutputPathOnError, JSON.stringify(errorReport, null, 2));
505
- console.warn(`PlaywrightPulseReporter: Wrote an error report to ${finalOutputPathOnError} as finalReport was missing.`);
464
+ // Stringify with Date conversion for the minimal error report
465
+ await fs.writeFile(errorPath, JSON.stringify(errorReportMinimal, (key, value) => value instanceof Date ? value.toISOString() : value, 2));
466
+ console.warn(`PlaywrightPulseReporter: Wrote a minimal error report to ${errorPath}.`);
506
467
  }
507
- catch (writeError) {
508
- console.error(`PlaywrightPulseReporter: Failed to write error report: ${writeError.message}`);
468
+ catch (e) {
469
+ console.error("PlaywrightPulseReporter: Failed to write minimal error report.", e);
509
470
  }
510
471
  return;
511
472
  }
473
+ // At this point, finalReport.run is guaranteed to be populated by either _mergeShardResults or the non-sharded path.
512
474
  const reportRunData = finalReport.run;
513
- const finalRunStatus = ((_a = reportRunData === null || reportRunData === void 0 ? void 0 : reportRunData.failed) !== null && _a !== void 0 ? _a : 0) > 0
475
+ const finalRunStatus = ((_a = reportRunData.failed) !== null && _a !== void 0 ? _a : 0) > 0
514
476
  ? "failed"
515
- : ((_b = reportRunData === null || reportRunData === void 0 ? void 0 : reportRunData.totalTests) !== null && _b !== void 0 ? _b : 0) === 0 && result.status !== "passed"
477
+ : ((_b = reportRunData.totalTests) !== null && _b !== void 0 ? _b : 0) === 0 && result.status !== "passed"
516
478
  ? result.status === "interrupted"
517
479
  ? "interrupted"
518
480
  : "no tests or error"
@@ -521,11 +483,11 @@ PlaywrightPulseReporter: Run Finished
521
483
  PlaywrightPulseReporter: Run Finished
522
484
  -----------------------------------------
523
485
  Overall Status: ${finalRunStatus.toUpperCase()}
524
- Total Tests: ${(reportRunData === null || reportRunData === void 0 ? void 0 : reportRunData.totalTests) || 0}
525
- Passed: ${reportRunData === null || reportRunData === void 0 ? void 0 : reportRunData.passed}
526
- Failed: ${reportRunData === null || reportRunData === void 0 ? void 0 : reportRunData.failed}
527
- Skipped: ${reportRunData === null || reportRunData === void 0 ? void 0 : reportRunData.skipped}
528
- Duration: ${(((_c = reportRunData === null || reportRunData === void 0 ? void 0 : reportRunData.duration) !== null && _c !== void 0 ? _c : 0) / 1000).toFixed(2)}s
486
+ Total Tests: ${reportRunData.totalTests}
487
+ Passed: ${reportRunData.passed}
488
+ Failed: ${reportRunData.failed}
489
+ Skipped: ${reportRunData.skipped}
490
+ Duration: ${(reportRunData.duration / 1000).toFixed(2)}s
529
491
  -----------------------------------------`;
530
492
  if (this.printsToStdio()) {
531
493
  console.log(summary);
@@ -533,11 +495,11 @@ PlaywrightPulseReporter: Run Finished
533
495
  const finalOutputPath = path.join(this.outputDir, this.baseOutputFile);
534
496
  try {
535
497
  await this._ensureDirExists(this.outputDir);
498
+ // Custom replacer for JSON.stringify to handle Date objects correctly
536
499
  await fs.writeFile(finalOutputPath, JSON.stringify(finalReport, (key, value) => {
537
- if (value instanceof Date)
500
+ if (value instanceof Date) {
538
501
  return value.toISOString();
539
- if (typeof value === "bigint")
540
- return value.toString();
502
+ }
541
503
  return value;
542
504
  }, 2));
543
505
  if (this.printsToStdio()) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@arghajit/dummy",
3
3
  "author": "Arghajit Singha",
4
- "version": "0.1.0-beta-5",
4
+ "version": "0.1.0-beta-7",
5
5
  "description": "A Playwright reporter and dashboard for visualizing test results.",
6
6
  "keywords": [
7
7
  "playwright",