@arghajit/dummy 0.1.0-beta-19 → 0.1.0-beta-20

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.
package/README.md CHANGED
@@ -161,8 +161,8 @@ npx generate-report
161
161
  1. Configure `.env`:
162
162
 
163
163
  ```bash
164
- SENDER_EMAIL_1=recipient1@example.com
165
- SENDER_EMAIL_2=recipient2@example.com
164
+ RECIPIENT_EMAIL_1=recipient1@example.com
165
+ RECIPIENT_EMAIL_2=recipient2@example.com
166
166
  # ... up to 5 recipients
167
167
  ```
168
168
 
@@ -277,7 +277,7 @@ npm install @arghajit/playwright-pulse-report@latest
277
277
 
278
278
  ---
279
279
 
280
- <img src="https://ocpaxmghzmfbuhxzxzae.supabase.co/storage/v1/object/public/images//pulse-logo.png" alt="pulse dashboard" title="pulse dashboard" height="50px" width="80px" align="left" padding="10px"/>
280
+ <img src="https://ocpaxmghzmfbuhxzxzae.supabase.co/storage/v1/object/public/images//pulse-logo.png" alt="pulse dashboard" title="pulse dashboard" height="35px" width="60px" align="left" padding="5px"/>
281
281
  <h2>Pulse Dashboard</h2>
282
282
 
283
283
  **Real-time Playwright Test Monitoring & Analysis**
@@ -300,13 +300,13 @@ npm run pulse-dashboard
300
300
 
301
301
  *(Run from project root containing `pulse-report/` directory)*
302
302
 
303
- **NPM Package**: [pulse-dashboard on npm](https://www.npmjs.com/package/pulse-dashboard)
303
+ **NPM Package**: [pulse-dashboard](https://www.npmjs.com/package/pulse-dashboard)
304
304
 
305
305
  **Tech Stack**: Next.js, TypeScript, Tailwind CSS, Playwright
306
306
 
307
- *Part of the Playwright Pulse Report ecosystem*
307
+ *Part of the Playwright Pulse Report ecosystem*
308
308
 
309
- ---
309
+ ---
310
310
 
311
311
  ## 📬 Support
312
312
 
@@ -253,37 +253,47 @@ class PlaywrightPulseReporter {
253
253
  codeSnippet: codeSnippet,
254
254
  tags: test.tags.map((tag) => tag.startsWith("@") ? tag.substring(1) : tag),
255
255
  screenshots: [],
256
- videoPath: [], // MODIFIED: Initialized as an array
256
+ videoPath: [],
257
257
  tracePath: undefined,
258
- attachments: [], // NEW: Initialized
258
+ attachments: [],
259
259
  stdout: stdoutMessages.length > 0 ? stdoutMessages : undefined,
260
260
  stderr: stderrMessages.length > 0 ? stderrMessages : undefined,
261
261
  ...testSpecificData,
262
262
  };
263
- // --- NEW SELF-CONTAINED ATTACHMENT PROCESSING LOGIC ---
264
- for (const attachment of result.attachments) {
263
+ // --- CORRECTED ATTACHMENT PROCESSING LOGIC ---
264
+ for (const [index, attachment] of result.attachments.entries()) {
265
265
  if (!attachment.path)
266
266
  continue;
267
267
  try {
268
- const attachmentFileName = path.basename(attachment.path);
269
- const relativeDestPath = path.join(ATTACHMENTS_SUBDIR, attachmentFileName);
268
+ // Create a sanitized, unique folder name for this specific test
269
+ const testSubfolder = test.id.replace(/[^a-zA-Z0-9_-]/g, "_");
270
+ // Sanitize the original attachment name to create a safe filename
271
+ const safeAttachmentName = path
272
+ .basename(attachment.path)
273
+ .replace(/[^a-zA-Z0-9_.-]/g, "_");
274
+ // Create a unique filename to prevent collisions, especially in retries
275
+ const uniqueFileName = `${index}-${Date.now()}-${safeAttachmentName}`;
276
+ // This is the relative path that will be stored in the JSON report
277
+ const relativeDestPath = path.join(ATTACHMENTS_SUBDIR, testSubfolder, uniqueFileName);
278
+ // This is the absolute path used for the actual file system operation
270
279
  const absoluteDestPath = path.join(this.outputDir, relativeDestPath);
280
+ // Ensure the unique, test-specific attachment directory exists
271
281
  await this._ensureDirExists(path.dirname(absoluteDestPath));
272
282
  await fs.copyFile(attachment.path, absoluteDestPath);
283
+ // Categorize the attachment based on its content type
273
284
  if (attachment.contentType.startsWith("image/")) {
274
285
  (_j = pulseResult.screenshots) === null || _j === void 0 ? void 0 : _j.push(relativeDestPath);
275
286
  }
276
287
  else if (attachment.contentType.startsWith("video/")) {
277
- (_k = pulseResult.videoPath) === null || _k === void 0 ? void 0 : _k.push(relativeDestPath); // MODIFIED: Push to videoPath array
288
+ (_k = pulseResult.videoPath) === null || _k === void 0 ? void 0 : _k.push(relativeDestPath);
278
289
  }
279
290
  else if (attachment.name === "trace") {
280
291
  pulseResult.tracePath = relativeDestPath;
281
292
  }
282
293
  else {
283
- // NEW: Handle all other file types
284
294
  (_l = pulseResult.attachments) === null || _l === void 0 ? void 0 : _l.push({
285
- name: attachment.name,
286
- path: relativeDestPath,
295
+ name: attachment.name, // The original, human-readable name
296
+ path: relativeDestPath, // The safe, relative path for linking
287
297
  contentType: attachment.contentType,
288
298
  });
289
299
  }
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "@arghajit/dummy",
3
3
  "author": "Arghajit Singha",
4
- "version": "0.1.0-beta-19",
4
+ "version": "0.1.0-beta-20",
5
5
  "description": "A Playwright reporter and dashboard for visualizing test results.",
6
+ "homepage": "https://playwright-pulse-report.netlify.app/",
6
7
  "keywords": [
7
8
  "playwright",
8
9
  "reporter",
@@ -15,7 +16,9 @@
15
16
  "report",
16
17
  "email-report",
17
18
  "send-report",
18
- "email"
19
+ "email",
20
+ "playwright-report",
21
+ "pulse"
19
22
  ],
20
23
  "main": "dist/reporter/index.js",
21
24
  "types": "dist/reporter/index.d.ts",
@@ -1409,6 +1409,11 @@ function generateHTML(reportData, trendData = null) {
1409
1409
  </div>
1410
1410
  <div class="test-case-content" style="display: none;">
1411
1411
  <p><strong>Full Path:</strong> ${sanitizeHTML(test.name)}</p>
1412
+ <p><strong>Test run Worker ID:</strong> ${sanitizeHTML(
1413
+ test.workerId
1414
+ )} [<strong>Total No. of Workers:</strong> ${sanitizeHTML(
1415
+ test.totalWorkers
1416
+ )}]</p>
1412
1417
  ${
1413
1418
  test.errorMessage
1414
1419
  ? `<div class="test-error-summary">${formatPlaywrightError(
@@ -1441,15 +1446,15 @@ function generateHTML(reportData, trendData = null) {
1441
1446
  ${
1442
1447
  test.stdout && test.stdout.length > 0
1443
1448
  ? `<div class="console-output-section"><h4>Console Output (stdout)</h4><pre class="console-log stdout-log" style="background-color: #2d2d2d; color: wheat; padding: 1.25em; border-radius: 0.85em; line-height: 1.2;">${formatPlaywrightError(
1444
- test.stdout.join("\n")
1449
+ test.stdout.map((line) => sanitizeHTML(line)).join("\n")
1445
1450
  )}</pre></div>`
1446
1451
  : ""
1447
1452
  }
1448
1453
  ${
1449
1454
  test.stderr && test.stderr.length > 0
1450
- ? `<div class="console-output-section"><h4>Console Output (stderr)</h4><pre class="console-log stderr-log" style="background-color: #2d2d2d; color: indianred; padding: 1.25em; border-radius: 0.85em; line-height: 1.2;">${test.stderr
1451
- .map((line) => sanitizeHTML(line))
1452
- .join("\n")}</pre></div>`
1455
+ ? `<div class="console-output-section"><h4>Console Output (stderr)</h4><pre class="console-log stderr-log" style="background-color: #2d2d2d; color: indianred; padding: 1.25em; border-radius: 0.85em; line-height: 1.2;">${formatPlaywrightError(
1456
+ test.stderr.map((line) => sanitizeHTML(line)).join("\n")
1457
+ )}</pre></div>`
1453
1458
  : ""
1454
1459
  }
1455
1460
  ${
@@ -1480,11 +1485,7 @@ function generateHTML(reportData, trendData = null) {
1480
1485
  }
1481
1486
  ${
1482
1487
  test.videoPath && test.videoPath.length > 0
1483
- ? `
1484
- <div class="attachments-section">
1485
- <h4>Videos</h4>
1486
- <div class="attachments-grid">
1487
- ${test.videoPath
1488
+ ? `<div class="attachments-section"><h4>Videos</h4><div class="attachments-grid">${test.videoPath
1488
1489
  .map((videoUrl, index) => {
1489
1490
  const fileExtension = String(videoUrl)
1490
1491
  .split(".")
@@ -1498,8 +1499,7 @@ function generateHTML(reportData, trendData = null) {
1498
1499
  mov: "video/quicktime",
1499
1500
  avi: "video/x-msvideo",
1500
1501
  }[fileExtension] || "video/mp4";
1501
- return `
1502
- <div class="attachment-item video-item">
1502
+ return `<div class="attachment-item video-item">
1503
1503
  <video controls width="100%" height="auto" title="Video ${
1504
1504
  index + 1
1505
1505
  }">
@@ -1517,10 +1517,7 @@ function generateHTML(reportData, trendData = null) {
1517
1517
  </div>
1518
1518
  </div>`;
1519
1519
  })
1520
- .join("")}
1521
- </div>
1522
- </div>
1523
- `
1520
+ .join("")}</div></div>`
1524
1521
  : ""
1525
1522
  }
1526
1523
  ${
@@ -1592,8 +1589,8 @@ function generateHTML(reportData, trendData = null) {
1592
1589
  }
1593
1590
  ${
1594
1591
  test.codeSnippet
1595
- ? `<div class="code-section"><h4>Code Snippet</h4><pre><code>${sanitizeHTML(
1596
- test.codeSnippet
1592
+ ? `<div class="code-section"><h4>Code Snippet</h4><pre><code>${formatPlaywrightError(
1593
+ sanitizeHTML(test.codeSnippet)
1597
1594
  )}</code></pre></div>`
1598
1595
  : ""
1599
1596
  }
@@ -1377,6 +1377,11 @@ function generateHTML(reportData, trendData = null) {
1377
1377
  <p><strong>Full Path:</strong> ${sanitizeHTML(
1378
1378
  test.name
1379
1379
  )}</p>
1380
+ <p><strong>Test run Worker ID:</strong> ${sanitizeHTML(
1381
+ test.workerId
1382
+ )} [<strong>Total No. of Workers:</strong> ${sanitizeHTML(
1383
+ test.totalWorkers
1384
+ )}]</p>
1380
1385
  ${
1381
1386
  test.errorMessage
1382
1387
  ? `<div class="test-error-summary">${formatPlaywrightError(
@@ -1535,6 +1540,14 @@ function generateHTML(reportData, trendData = null) {
1535
1540
  })
1536
1541
  .join("")}</div></div>`;
1537
1542
  })()}
1543
+
1544
+ ${
1545
+ test.codeSnippet
1546
+ ? `<div class="code-section"><h4>Code Snippet</h4><pre><code>${sanitizeHTML(
1547
+ test.codeSnippet
1548
+ )}</code></pre></div>`
1549
+ : ""
1550
+ }
1538
1551
  </div>
1539
1552
  </div>`;
1540
1553
  })
@@ -1,6 +1,6 @@
1
+ #!/usr/bin/env node
1
2
  import * as fs from "fs/promises";
2
3
  import path from "path";
3
- // XLSX is NO LONGER NEEDED here
4
4
 
5
5
  // Use dynamic import for chalk as it's ESM only for prettier console logs
6
6
  let chalk;
@@ -265,11 +265,11 @@ const sendEmail = async (credentials) => {
265
265
  const mailOptions = {
266
266
  from: credentials.username,
267
267
  to: [
268
- process.env.SENDER_EMAIL_1 || "",
269
- process.env.SENDER_EMAIL_2 || "",
270
- process.env.SENDER_EMAIL_3 || "",
271
- process.env.SENDER_EMAIL_4 || "",
272
- process.env.SENDER_EMAIL_5 || "",
268
+ process.env.RECIPIENT_EMAIL_1 || "",
269
+ process.env.RECIPIENT_EMAIL_2 || "",
270
+ process.env.RECIPIENT_EMAIL_3 || "",
271
+ process.env.RECIPIENT_EMAIL_4 || "",
272
+ process.env.RECIPIENT_EMAIL_5 || "",
273
273
  ].filter((email) => email), // Filter out empty strings
274
274
  subject: "Pulse Report " + new Date().toLocaleString(),
275
275
  html: htmlContent,