ortoni-report 2.0.2 → 2.0.3

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/changelog.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Change Log:
2
2
 
3
+ ## Version 2.0.3
4
+
5
+ #### 🚀 New Features
6
+ - **Add screenshot attachment as pagination**: Now supports adding screenshot attachments for easier navigation and pagination.
7
+ - **Bulma Inline CSS**: Integrated Bulma inline CSS for improved styling.
8
+ - **Show card if the count has value**: Cards will now appear only when a valid count is present.
9
+ - **Folder Path**: Introduced a new feature to store the result in the folder path.
10
+
11
+ #### ✨ Improvements
12
+ - **Chart JS as CDN**: Enhanced performance by switching Chart.js to be served via CDN.
13
+ - **Theme icon, navbar & summary icons**: Refined the design of theme icons, navbar, and summary icons for a better user experience.
14
+ - **User meta icons**: Updated and improved the appearance of user meta icons.
15
+ - **Show selected filter on nav-end**: Filters now appear on the nav-end when selected.
16
+ - **Filter logic**: Improved filter functionality by only displaying the filtered items, avoiding the use of the `includes` method.
17
+ - **Logo link to page**: Clicking on the logo now navigates to the corresponding page.
18
+ - **Minor tweaks**: Enhanced overall UI experience
19
+
3
20
  ## Version 2.0.2
4
21
 
5
22
  #### 🚀 New Features
@@ -53,6 +53,11 @@ interface OrtoniReportConfig {
53
53
  * @example "index.html"
54
54
  */
55
55
  filename?: string;
56
+ /**
57
+ * The folder name.
58
+ * @example "playwright-report"
59
+ */
60
+ folderPath?: string;
56
61
  }
57
62
 
58
63
  interface Steps {
@@ -76,6 +81,7 @@ interface TestResultData {
76
81
  steps: Steps[];
77
82
  logs: string;
78
83
  screenshotPath?: string | null | undefined;
84
+ screenshots?: string[];
79
85
  filePath: string;
80
86
  filters: Set<string>;
81
87
  tracePath?: string;
@@ -90,15 +96,16 @@ declare class OrtoniReport implements Reporter {
90
96
  private suiteName;
91
97
  private config;
92
98
  private projectSet;
93
- private tagsSet;
99
+ private folderPath;
94
100
  constructor(config?: OrtoniReportConfig);
95
101
  onBegin(config: FullConfig, suite: Suite): void;
96
102
  onTestBegin(test: TestCase, result: TestResult): void;
97
103
  onTestEnd(test: TestCase, result: TestResult): void;
98
104
  private attachFiles;
99
105
  onEnd(result: FullResult): void;
106
+ private registerPartial;
100
107
  private groupResults;
101
- generateHTML(filteredResults: TestResultData[], totalDuration: string): string;
108
+ generateHTML(filteredResults: TestResultData[], totalDuration: string, cssContent: string): string;
102
109
  }
103
110
 
104
111
  export { OrtoniReportConfig, OrtoniReport as default };
@@ -6623,12 +6623,15 @@ var OrtoniReport = class {
6623
6623
  this.results = [];
6624
6624
  this.groupedResults = {};
6625
6625
  this.projectSet = /* @__PURE__ */ new Set();
6626
- this.tagsSet = /* @__PURE__ */ new Set();
6627
6626
  this.config = config;
6627
+ this.folderPath = config.folderPath || "playwright-report";
6628
6628
  }
6629
6629
  onBegin(config, suite) {
6630
6630
  this.results = [];
6631
6631
  this.projectRoot = config.rootDir;
6632
+ if (!import_fs.default.existsSync(this.folderPath)) {
6633
+ import_fs.default.mkdirSync(this.folderPath, { recursive: true });
6634
+ }
6632
6635
  }
6633
6636
  onTestBegin(test, result) {
6634
6637
  }
@@ -6683,35 +6686,34 @@ var OrtoniReport = class {
6683
6686
  attachFiles(result, testResult) {
6684
6687
  if (result.attachments) {
6685
6688
  const { base64Image } = this.config;
6686
- const screenshot = result.attachments.find(
6687
- (attachment) => attachment.name === "screenshot"
6688
- );
6689
- if (screenshot && screenshot.path) {
6690
- try {
6691
- const screenshotContent = import_fs.default.readFileSync(
6692
- screenshot.path,
6693
- base64Image ? "base64" : void 0
6694
- );
6695
- testResult.screenshotPath = base64Image ? `data:image/png;base64,${screenshotContent}` : import_path2.default.resolve(screenshot.path);
6696
- } catch (error) {
6697
- console.error(
6698
- `OrtoniReport: Failed to read screenshot file: ${screenshot.path}`,
6699
- error
6700
- );
6689
+ testResult.screenshots = [];
6690
+ result.attachments.forEach((attachment) => {
6691
+ if (attachment.contentType === "image/png") {
6692
+ let screenshotPath = "";
6693
+ if (attachment.path) {
6694
+ try {
6695
+ const screenshotContent = import_fs.default.readFileSync(
6696
+ attachment.path,
6697
+ base64Image ? "base64" : void 0
6698
+ );
6699
+ screenshotPath = base64Image ? `data:image/png;base64,${screenshotContent}` : import_path2.default.resolve(attachment.path);
6700
+ } catch (error) {
6701
+ console.error(
6702
+ `OrtoniReport: Failed to read screenshot file: ${attachment.path}`,
6703
+ error
6704
+ );
6705
+ }
6706
+ } else if (attachment.body) {
6707
+ screenshotPath = `data:image/png;base64,${attachment.body.toString("base64")}`;
6708
+ }
6709
+ if (screenshotPath) {
6710
+ testResult.screenshots?.push(screenshotPath);
6711
+ }
6701
6712
  }
6702
- }
6703
- const tracePath = result.attachments.find(
6704
- (attachment) => attachment.name === "trace"
6705
- );
6706
- if (tracePath?.path) {
6707
- testResult.tracePath = import_path2.default.resolve(__dirname, tracePath.path);
6708
- }
6709
- const videoPath = result.attachments.find(
6710
- (attachment) => attachment.name === "video"
6711
- );
6712
- if (videoPath?.path) {
6713
- testResult.videoPath = import_path2.default.resolve(__dirname, videoPath.path);
6714
- }
6713
+ if (attachment.name === "video" && attachment.path) {
6714
+ testResult.videoPath = import_path2.default.resolve(__dirname, attachment.path);
6715
+ }
6716
+ });
6715
6717
  }
6716
6718
  }
6717
6719
  onEnd(result) {
@@ -6727,17 +6729,36 @@ var OrtoniReport = class {
6727
6729
  "eq",
6728
6730
  (actualStatus, expectedStatus) => actualStatus === expectedStatus
6729
6731
  );
6732
+ import_handlebars.default.registerHelper("gr", (count) => count > 0);
6733
+ const cssContent = import_fs.default.readFileSync(
6734
+ import_path2.default.resolve(__dirname, "style", "main.css"),
6735
+ "utf-8"
6736
+ );
6737
+ this.registerPartial("navbar");
6738
+ this.registerPartial("testStatus");
6739
+ this.registerPartial("testPanel");
6740
+ this.registerPartial("summaryCard");
6741
+ this.registerPartial("userInfo");
6730
6742
  const outputFilename = ensureHtmlExtension(
6731
6743
  this.config.filename || "ortoni-report.html"
6732
6744
  );
6733
- const html = this.generateHTML(filteredResults, totalDuration);
6734
- const outputPath = import_path2.default.resolve(process.cwd(), outputFilename);
6745
+ if (!import_fs.default.existsSync(this.folderPath)) {
6746
+ import_fs.default.mkdirSync(this.folderPath, { recursive: true });
6747
+ }
6748
+ const html = this.generateHTML(filteredResults, totalDuration, cssContent);
6749
+ const outputPath = import_path2.default.join(process.cwd(), this.folderPath, outputFilename);
6735
6750
  import_fs.default.writeFileSync(outputPath, html);
6736
6751
  console.log(`Ortoni HTML report generated at ${outputPath}`);
6737
6752
  } catch (error) {
6738
6753
  console.error("OrtoniReport: Error generating report:", error);
6739
6754
  }
6740
6755
  }
6756
+ registerPartial(name) {
6757
+ import_handlebars.default.registerPartial(name, import_fs.default.readFileSync(
6758
+ import_path2.default.resolve(__dirname, "views", name + ".hbs"),
6759
+ "utf-8"
6760
+ ));
6761
+ }
6741
6762
  groupResults() {
6742
6763
  if (this.config.showProject) {
6743
6764
  this.groupedResults = this.results.reduce((acc, result, index) => {
@@ -6758,7 +6779,7 @@ var OrtoniReport = class {
6758
6779
  }, {});
6759
6780
  }
6760
6781
  }
6761
- generateHTML(filteredResults, totalDuration) {
6782
+ generateHTML(filteredResults, totalDuration, cssContent) {
6762
6783
  try {
6763
6784
  const totalTests = filteredResults.length;
6764
6785
  const passedTests = this.results.filter(
@@ -6770,14 +6791,13 @@ var OrtoniReport = class {
6770
6791
  ).length;
6771
6792
  const successRate = ((passedTests + flakyTests) / totalTests * 100).toFixed(2);
6772
6793
  const templateSource = import_fs.default.readFileSync(
6773
- import_path2.default.resolve(__dirname, "report-template.hbs"),
6794
+ import_path2.default.resolve(__dirname, "views", "main.hbs"),
6774
6795
  "utf-8"
6775
6796
  );
6776
6797
  const template = import_handlebars.default.compile(templateSource);
6777
6798
  const logo = this.config.logo ? import_path2.default.resolve(this.config.logo) : void 0;
6778
6799
  const allTags = /* @__PURE__ */ new Set();
6779
6800
  this.results.forEach((result) => {
6780
- result.suiteTags.forEach((tag) => allTags.add(tag));
6781
6801
  result.testTags.forEach((tag) => allTags.add(tag));
6782
6802
  });
6783
6803
  const data = {
@@ -6803,7 +6823,7 @@ var OrtoniReport = class {
6803
6823
  showProject: this.config.showProject || false,
6804
6824
  title: this.config.title || "Ortoni Playwright Test Report"
6805
6825
  };
6806
- return template(data);
6826
+ return template({ ...data, inlineCss: cssContent });
6807
6827
  } catch (error) {
6808
6828
  console.error("OrtoniReport: Error generating HTML:", error);
6809
6829
  return `<html><body><h1>Report generation failed</h1><pre>${error.stack}</pre></body></html>`;
@@ -6619,12 +6619,15 @@ var OrtoniReport = class {
6619
6619
  this.results = [];
6620
6620
  this.groupedResults = {};
6621
6621
  this.projectSet = /* @__PURE__ */ new Set();
6622
- this.tagsSet = /* @__PURE__ */ new Set();
6623
6622
  this.config = config;
6623
+ this.folderPath = config.folderPath || "playwright-report";
6624
6624
  }
6625
6625
  onBegin(config, suite) {
6626
6626
  this.results = [];
6627
6627
  this.projectRoot = config.rootDir;
6628
+ if (!fs.existsSync(this.folderPath)) {
6629
+ fs.mkdirSync(this.folderPath, { recursive: true });
6630
+ }
6628
6631
  }
6629
6632
  onTestBegin(test, result) {
6630
6633
  }
@@ -6679,35 +6682,34 @@ var OrtoniReport = class {
6679
6682
  attachFiles(result, testResult) {
6680
6683
  if (result.attachments) {
6681
6684
  const { base64Image } = this.config;
6682
- const screenshot = result.attachments.find(
6683
- (attachment) => attachment.name === "screenshot"
6684
- );
6685
- if (screenshot && screenshot.path) {
6686
- try {
6687
- const screenshotContent = fs.readFileSync(
6688
- screenshot.path,
6689
- base64Image ? "base64" : void 0
6690
- );
6691
- testResult.screenshotPath = base64Image ? `data:image/png;base64,${screenshotContent}` : path2.resolve(screenshot.path);
6692
- } catch (error) {
6693
- console.error(
6694
- `OrtoniReport: Failed to read screenshot file: ${screenshot.path}`,
6695
- error
6696
- );
6685
+ testResult.screenshots = [];
6686
+ result.attachments.forEach((attachment) => {
6687
+ if (attachment.contentType === "image/png") {
6688
+ let screenshotPath = "";
6689
+ if (attachment.path) {
6690
+ try {
6691
+ const screenshotContent = fs.readFileSync(
6692
+ attachment.path,
6693
+ base64Image ? "base64" : void 0
6694
+ );
6695
+ screenshotPath = base64Image ? `data:image/png;base64,${screenshotContent}` : path2.resolve(attachment.path);
6696
+ } catch (error) {
6697
+ console.error(
6698
+ `OrtoniReport: Failed to read screenshot file: ${attachment.path}`,
6699
+ error
6700
+ );
6701
+ }
6702
+ } else if (attachment.body) {
6703
+ screenshotPath = `data:image/png;base64,${attachment.body.toString("base64")}`;
6704
+ }
6705
+ if (screenshotPath) {
6706
+ testResult.screenshots?.push(screenshotPath);
6707
+ }
6697
6708
  }
6698
- }
6699
- const tracePath = result.attachments.find(
6700
- (attachment) => attachment.name === "trace"
6701
- );
6702
- if (tracePath?.path) {
6703
- testResult.tracePath = path2.resolve(__dirname, tracePath.path);
6704
- }
6705
- const videoPath = result.attachments.find(
6706
- (attachment) => attachment.name === "video"
6707
- );
6708
- if (videoPath?.path) {
6709
- testResult.videoPath = path2.resolve(__dirname, videoPath.path);
6710
- }
6709
+ if (attachment.name === "video" && attachment.path) {
6710
+ testResult.videoPath = path2.resolve(__dirname, attachment.path);
6711
+ }
6712
+ });
6711
6713
  }
6712
6714
  }
6713
6715
  onEnd(result) {
@@ -6723,17 +6725,36 @@ var OrtoniReport = class {
6723
6725
  "eq",
6724
6726
  (actualStatus, expectedStatus) => actualStatus === expectedStatus
6725
6727
  );
6728
+ import_handlebars.default.registerHelper("gr", (count) => count > 0);
6729
+ const cssContent = fs.readFileSync(
6730
+ path2.resolve(__dirname, "style", "main.css"),
6731
+ "utf-8"
6732
+ );
6733
+ this.registerPartial("navbar");
6734
+ this.registerPartial("testStatus");
6735
+ this.registerPartial("testPanel");
6736
+ this.registerPartial("summaryCard");
6737
+ this.registerPartial("userInfo");
6726
6738
  const outputFilename = ensureHtmlExtension(
6727
6739
  this.config.filename || "ortoni-report.html"
6728
6740
  );
6729
- const html = this.generateHTML(filteredResults, totalDuration);
6730
- const outputPath = path2.resolve(process.cwd(), outputFilename);
6741
+ if (!fs.existsSync(this.folderPath)) {
6742
+ fs.mkdirSync(this.folderPath, { recursive: true });
6743
+ }
6744
+ const html = this.generateHTML(filteredResults, totalDuration, cssContent);
6745
+ const outputPath = path2.join(process.cwd(), this.folderPath, outputFilename);
6731
6746
  fs.writeFileSync(outputPath, html);
6732
6747
  console.log(`Ortoni HTML report generated at ${outputPath}`);
6733
6748
  } catch (error) {
6734
6749
  console.error("OrtoniReport: Error generating report:", error);
6735
6750
  }
6736
6751
  }
6752
+ registerPartial(name) {
6753
+ import_handlebars.default.registerPartial(name, fs.readFileSync(
6754
+ path2.resolve(__dirname, "views", name + ".hbs"),
6755
+ "utf-8"
6756
+ ));
6757
+ }
6737
6758
  groupResults() {
6738
6759
  if (this.config.showProject) {
6739
6760
  this.groupedResults = this.results.reduce((acc, result, index) => {
@@ -6754,7 +6775,7 @@ var OrtoniReport = class {
6754
6775
  }, {});
6755
6776
  }
6756
6777
  }
6757
- generateHTML(filteredResults, totalDuration) {
6778
+ generateHTML(filteredResults, totalDuration, cssContent) {
6758
6779
  try {
6759
6780
  const totalTests = filteredResults.length;
6760
6781
  const passedTests = this.results.filter(
@@ -6766,14 +6787,13 @@ var OrtoniReport = class {
6766
6787
  ).length;
6767
6788
  const successRate = ((passedTests + flakyTests) / totalTests * 100).toFixed(2);
6768
6789
  const templateSource = fs.readFileSync(
6769
- path2.resolve(__dirname, "report-template.hbs"),
6790
+ path2.resolve(__dirname, "views", "main.hbs"),
6770
6791
  "utf-8"
6771
6792
  );
6772
6793
  const template = import_handlebars.default.compile(templateSource);
6773
6794
  const logo = this.config.logo ? path2.resolve(this.config.logo) : void 0;
6774
6795
  const allTags = /* @__PURE__ */ new Set();
6775
6796
  this.results.forEach((result) => {
6776
- result.suiteTags.forEach((tag) => allTags.add(tag));
6777
6797
  result.testTags.forEach((tag) => allTags.add(tag));
6778
6798
  });
6779
6799
  const data = {
@@ -6799,7 +6819,7 @@ var OrtoniReport = class {
6799
6819
  showProject: this.config.showProject || false,
6800
6820
  title: this.config.title || "Ortoni Playwright Test Report"
6801
6821
  };
6802
- return template(data);
6822
+ return template({ ...data, inlineCss: cssContent });
6803
6823
  } catch (error) {
6804
6824
  console.error("OrtoniReport: Error generating HTML:", error);
6805
6825
  return `<html><body><h1>Report generation failed</h1><pre>${error.stack}</pre></body></html>`;