diff --git a/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ReportBehaviour/AssetBehaviour.js b/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ReportBehaviour/AssetBehaviour.js index 862a0f14..803f4863 100644 --- a/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ReportBehaviour/AssetBehaviour.js +++ b/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ReportBehaviour/AssetBehaviour.js @@ -6,7 +6,7 @@ export class AssetBehaviour { #assetModel; initialise() { - this.#linkElement.textContent = this.#assetModel.FileSummary; + this.#linkElement.textContent = this.#assetModel.Summary; if(imageTypes.includes(this.#assetModel.ContentType)) this.#initialiseImage(); @@ -16,23 +16,23 @@ export class AssetBehaviour { #initialiseImage() { this.#linkElement.addEventListener('click', ev => { - const usesBlobUrl = !!this.#assetModel.FileData - const url = usesBlobUrl ? this.#getBlobUrl() : this.#assetModel.FilePath; - this.#litebox.open(url, this.#assetModel.FileName, this.#assetModel.FileSummary, usesBlobUrl); + const usesBlobUrl = !!this.#assetModel.Data + const url = usesBlobUrl ? this.#getBlobUrl() : this.#assetModel.Path; + this.#litebox.open(url, this.#assetModel.Name, this.#assetModel.Summary, usesBlobUrl); ev.preventDefault(); }); this.#linkElement.href = null; } #initialiseDownload() { - const usesBlobUrl = !!this.#assetModel.FileData - const url = usesBlobUrl ? this.#getBlobUrl() : this.#assetModel.FilePath; + const usesBlobUrl = !!this.#assetModel.Data + const url = usesBlobUrl ? this.#getBlobUrl() : this.#assetModel.Path; this.#linkElement.href = url; - this.#linkElement.download = this.#assetModel.FileName; + this.#linkElement.download = this.#assetModel.Name; } #getBlobUrl() { - const dataBytes = this.#base64ToBytes(this.#assetModel.FileData); + const dataBytes = this.#base64ToBytes(this.#assetModel.Data); const blob = new Blob([dataBytes], { type: this.#assetModel.ContentType }); return URL.createObjectURL(blob); } diff --git a/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ReportLoader.js b/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ReportLoader.js index 07987aec..e65a5e48 100644 --- a/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ReportLoader.js +++ b/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ReportLoader.js @@ -28,7 +28,7 @@ export class ReportLoader { return { Metadata: { Timestamp: new Date(), - ReportFormatVersion: "0.0.0", + ReportVersion: "0.0.0", }, Performances: [], }; diff --git a/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ReportLoader.spec.js b/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ReportLoader.spec.js index f4ad3b15..0c5f3e08 100644 --- a/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ReportLoader.spec.js +++ b/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ReportLoader.spec.js @@ -30,7 +30,7 @@ test('ReportLoader should return an empty report if the specified script element expect(jsonData).toEqual({ Metadata: { Timestamp: new Date(), - ReportFormatVersion: "0.0.0", + ReportVersion: "0.0.0", }, Performances: [], }); diff --git a/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ReportWriter/FeatureElementCreator.js b/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ReportWriter/FeatureElementCreator.js index de958cb8..16bb452a 100644 --- a/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ReportWriter/FeatureElementCreator.js +++ b/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ReportWriter/FeatureElementCreator.js @@ -19,8 +19,8 @@ export class FeatureElementCreator { featureElement.querySelector('.featureName').addEventListener('click', ev => ev.currentTarget.parentElement.classList.toggle('collapsed')); const featureIdentifierElement = featureElement.querySelector('.featureIdentifier'); - if (feature.feature && !feature.feature.WasIdentifierAutoGenerated) - featureIdentifierElement.textContent = feature.feature.Identifier; + if (feature.feature && !feature.feature.IsGeneratedId) + featureIdentifierElement.textContent = feature.feature.Id; else featureIdentifierElement.remove(); diff --git a/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ReportWriter/ReportWriter.spec.js b/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ReportWriter/ReportWriter.spec.js index 2d99a20b..bf989144 100644 --- a/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ReportWriter/ReportWriter.spec.js +++ b/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ReportWriter/ReportWriter.spec.js @@ -28,120 +28,120 @@ const testData = { { "Identifier": "6077245f-9245-4021-adab-cedf66d414fb", "Name": "Adding up numbers", - "WasIdentifierAutoGenerated": true + "IsGeneratedId": true }, { "Identifier": "0b2bd6e4-4b73-4d92-a451-7b8dbcabb9e7", "Name": "Mathias should be able to add three numbers in a single step", - "WasIdentifierAutoGenerated": true + "IsGeneratedId": true } ], "Outcome": "Success", "Reportables": [ { - "Type": "ActorCreatedReport", + "Kind": "ActorCreatedReport", "Report": "Mathias joined the performance", - "ActorName": "Mathias" + "Actor": "Mathias" }, { - "Type": "ActorGainedAbilityReport", + "Kind": "ActorGainedAbilityReport", "Report": "Mathias is able to add numbers to a running total", - "ActorName": "Mathias" + "Actor": "Mathias" }, { - "Type": "ActorSpotlitReport", + "Kind": "ActorSpotlitReport", "Report": "Mathias was put into the spotlight", - "ActorName": "Mathias" + "Actor": "Mathias" }, { - "Type": "PerformableReport", - "PerformableType": "CSF.Screenplay.AddingUp.SetTheNumber", - "PerformancePhase": "Given", + "Kind": "PerformableReport", + "Type": "CSF.Screenplay.AddingUp.SetTheNumber", + "Phase": "Given", "Result": null, "HasResult": false, "Exception": null, - "ExceptionIsFromConsumedPerformable": false, + "ExceptionIsBubbling": false, "Assets": [ { - "FilePath": "abc.txt", - "FileSummary": "A text file", + "Path": "abc.txt", + "Summary": "A text file", "ContentType": "text/plain" }, { - "FilePath": "one.png", - "FileSummary": "A picture", + "Path": "one.png", + "Summary": "A picture", "ContentType": "image/png" } ], "Reportables": [], "Report": "Mathias sets the running total to 50", - "ActorName": "Mathias" + "Actor": "Mathias" }, { - "Type": "PerformableReport", - "PerformableType": "CSF.Screenplay.AddingUp.AddThreeNumbers", - "PerformancePhase": "When", + "Kind": "PerformableReport", + "Type": "CSF.Screenplay.AddingUp.AddThreeNumbers", + "Phase": "When", "Result": null, "HasResult": false, "Exception": null, - "ExceptionIsFromConsumedPerformable": false, + "ExceptionIsBubbling": false, "Assets": [], "Reportables": [ { - "Type": "PerformableReport", - "PerformableType": "CSF.Screenplay.AddingUp.AddTheNumber", - "PerformancePhase": "", + "Kind": "PerformableReport", + "Type": "CSF.Screenplay.AddingUp.AddTheNumber", + "Phase": "", "Result": null, "HasResult": false, "Exception": null, - "ExceptionIsFromConsumedPerformable": false, + "ExceptionIsBubbling": false, "Assets": [], "Reportables": [], "Report": "Mathias adds 40 to the running total", - "ActorName": "Mathias" + "Actor": "Mathias" }, { - "Type": "PerformableReport", - "PerformableType": "CSF.Screenplay.AddingUp.AddTheNumber", - "PerformancePhase": "", + "Kind": "PerformableReport", + "Type": "CSF.Screenplay.AddingUp.AddTheNumber", + "Phase": "", "Result": null, "HasResult": false, "Exception": null, - "ExceptionIsFromConsumedPerformable": false, + "ExceptionIsBubbling": false, "Assets": [], "Reportables": [], "Report": "Mathias adds 30 to the running total", - "ActorName": "Mathias" + "Actor": "Mathias" }, { - "Type": "PerformableReport", - "PerformableType": "CSF.Screenplay.AddingUp.AddTheNumber", - "PerformancePhase": "", + "Kind": "PerformableReport", + "Type": "CSF.Screenplay.AddingUp.AddTheNumber", + "Phase": "", "Result": null, "HasResult": false, "Exception": null, - "ExceptionIsFromConsumedPerformable": false, + "ExceptionIsBubbling": false, "Assets": [], "Reportables": [], "Report": "Mathias adds 20 to the running total", - "ActorName": "Mathias" + "Actor": "Mathias" } ], "Report": "Mathias adds three numbers to the running total: 40, 30 \u0026 20", - "ActorName": "Mathias" + "Actor": "Mathias" }, { - "Type": "PerformableReport", - "PerformableType": "CSF.Screenplay.AddingUp.GetTheNumber", - "PerformancePhase": "Then", + "Kind": "PerformableReport", + "Type": "CSF.Screenplay.AddingUp.GetTheNumber", + "Phase": "Then", "Result": "140", "HasResult": true, "Exception": null, - "ExceptionIsFromConsumedPerformable": false, + "ExceptionIsBubbling": false, "Assets": [], "Reportables": [], "Report": "Mathias gets the running total", - "ActorName": "Mathias" + "Actor": "Mathias" } ] }, @@ -150,82 +150,82 @@ const testData = { { "Identifier": "6077245f-9245-4021-adab-cedf66d414fb", "Name": "Adding up numbers", - "WasIdentifierAutoGenerated": true + "IsGeneratedId": true }, { "Identifier": "8c3e2e1a-f141-4484-a7a9-ac84772eefa5", "Name": "Mathias should be able to add three numbers together and get the correct result", - "WasIdentifierAutoGenerated": true + "IsGeneratedId": true } ], "Outcome": "Success", "Reportables": [ { - "Type": "ActorCreatedReport", + "Kind": "ActorCreatedReport", "Report": "Mathias joined the performance", - "ActorName": "Mathias" + "Actor": "Mathias" }, { - "Type": "ActorGainedAbilityReport", + "Kind": "ActorGainedAbilityReport", "Report": "Mathias is able to add numbers to a running total", - "ActorName": "Mathias" + "Actor": "Mathias" }, { - "Type": "ActorSpotlitReport", + "Kind": "ActorSpotlitReport", "Report": "Mathias was put into the spotlight", - "ActorName": "Mathias" + "Actor": "Mathias" }, { - "Type": "PerformableReport", - "PerformableType": "CSF.Screenplay.AddingUp.SetTheNumber", - "PerformancePhase": "Given", + "Kind": "PerformableReport", + "Type": "CSF.Screenplay.AddingUp.SetTheNumber", + "Phase": "Given", "Result": null, "HasResult": false, "Exception": null, - "ExceptionIsFromConsumedPerformable": false, + "ExceptionIsBubbling": false, "Assets": [], "Reportables": [], "Report": "Mathias sets the running total to 50", - "ActorName": "Mathias" + "Actor": "Mathias" }, { - "Type": "PerformableReport", - "PerformableType": "CSF.Screenplay.AddingUp.AddTheNumber", - "PerformancePhase": "When", + "Kind": "PerformableReport", + "Type": "CSF.Screenplay.AddingUp.AddTheNumber", + "Phase": "When", "Result": null, "HasResult": false, "Exception": null, - "ExceptionIsFromConsumedPerformable": false, + "ExceptionIsBubbling": false, "Assets": [], "Reportables": [], "Report": "Mathias adds 70 to the running total", - "ActorName": "Mathias" + "Actor": "Mathias" }, { - "Type": "PerformableReport", - "PerformableType": "CSF.Screenplay.AddingUp.AddTheNumber", - "PerformancePhase": "When", + "Kind": "PerformableReport", + "Type": "CSF.Screenplay.AddingUp.AddTheNumber", + "Phase": "When", "Result": null, "HasResult": false, "Exception": null, - "ExceptionIsFromConsumedPerformable": false, + "ExceptionIsBubbling": false, "Assets": [], "Reportables": [], "Report": "Mathias adds 20 to the running total", - "ActorName": "Mathias" + "Actor": "Mathias" }, { - "Type": "PerformableReport", - "PerformableType": "CSF.Screenplay.AddingUp.GetTheNumber", - "PerformancePhase": "Then", + "Kind": "PerformableReport", + "Type": "CSF.Screenplay.AddingUp.GetTheNumber", + "Phase": "Then", "Result": "140", "HasResult": true, "Exception": null, - "ExceptionIsFromConsumedPerformable": false, + "ExceptionIsBubbling": false, "Assets": [], "Reportables": [], "Report": "Mathias gets the running total", - "ActorName": "Mathias" + "Actor": "Mathias" } ] }, @@ -234,69 +234,69 @@ const testData = { { "Identifier": "6077245f-9245-4021-adab-cedf66d414fb", "Name": "Adding up numbers", - "WasIdentifierAutoGenerated": true + "IsGeneratedId": true }, { "Identifier": "b6410a9a-b524-40a6-9332-19e3c69d0357", "Name": "Mathias should be able to add two numbers together and get the correct result", - "WasIdentifierAutoGenerated": true + "IsGeneratedId": true } ], "Outcome": "Success", "Reportables": [ { - "Type": "ActorCreatedReport", + "Kind": "ActorCreatedReport", "Report": "Mathias joined the performance", - "ActorName": "Mathias" + "Actor": "Mathias" }, { - "Type": "ActorGainedAbilityReport", + "Kind": "ActorGainedAbilityReport", "Report": "Mathias is able to add numbers to a running total", - "ActorName": "Mathias" + "Actor": "Mathias" }, { - "Type": "ActorSpotlitReport", + "Kind": "ActorSpotlitReport", "Report": "Mathias was put into the spotlight", - "ActorName": "Mathias" + "Actor": "Mathias" }, { - "Type": "PerformableReport", - "PerformableType": "CSF.Screenplay.AddingUp.SetTheNumber", - "PerformancePhase": "Given", + "Kind": "PerformableReport", + "Type": "CSF.Screenplay.AddingUp.SetTheNumber", + "Phase": "Given", "Result": null, "HasResult": false, "Exception": null, - "ExceptionIsFromConsumedPerformable": false, + "ExceptionIsBubbling": false, "Assets": [], "Reportables": [], "Report": "Mathias sets the running total to 50", - "ActorName": "Mathias" + "Actor": "Mathias" }, { - "Type": "PerformableReport", - "PerformableType": "CSF.Screenplay.AddingUp.AddTheNumber", - "PerformancePhase": "When", + "Kind": "PerformableReport", + "Type": "CSF.Screenplay.AddingUp.AddTheNumber", + "Phase": "When", "Result": null, "HasResult": false, "Exception": null, - "ExceptionIsFromConsumedPerformable": false, + "ExceptionIsBubbling": false, "Assets": [], "Reportables": [], "Report": "Mathias adds 70 to the running total", - "ActorName": "Mathias" + "Actor": "Mathias" }, { - "Type": "PerformableReport", - "PerformableType": "CSF.Screenplay.AddingUp.GetTheNumber", - "PerformancePhase": "Then", + "Kind": "PerformableReport", + "Type": "CSF.Screenplay.AddingUp.GetTheNumber", + "Phase": "Then", "Result": "120", "HasResult": true, "Exception": null, - "ExceptionIsFromConsumedPerformable": false, + "ExceptionIsBubbling": false, "Assets": [], "Reportables": [], "Report": "Mathias gets the running total", - "ActorName": "Mathias" + "Actor": "Mathias" } ] } diff --git a/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ReportWriter/ReportableElementCreator.js b/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ReportWriter/ReportableElementCreator.js index b8ff4d24..561d3d63 100644 --- a/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ReportWriter/ReportableElementCreator.js +++ b/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ReportWriter/ReportableElementCreator.js @@ -11,9 +11,9 @@ export class ReportableElementCreator { const reportableElement = this.templateElement.content.cloneNode(true); this.#setupReportableType(reportableElement, reportable); - setContentOrRemove(reportableElement, reportable, '.phase', r => r.PerformancePhase, r => r.PerformancePhase); + setContentOrRemove(reportableElement, reportable, '.phase', r => r.Phase, r => r.Phase); setContentOrRemove(reportableElement, reportable, '.report', r => r.Report, r => r.Report); - setContentOrRemove(reportableElement, reportable, '.exception', r => r.Exception && !r.ExceptionIsFromConsumedPerformable, r => r.Exception); + setContentOrRemove(reportableElement, reportable, '.exception', r => r.Exception && !r.ExceptionIsBubbling, r => r.Exception); this.#setupResult(reportableElement, reportable); this.#setupPerformableType(reportableElement, reportable); this.#setupAssets(reportableElement, reportable, litebox); @@ -24,8 +24,8 @@ export class ReportableElementCreator { #setupReportableType(reportableElement, reportable) { const typeElement = reportableElement.querySelector('.type'); - typeElement.classList.add(reportable.Type); - switch (reportable.Type) { + typeElement.classList.add(reportable.Kind); + switch (reportable.Kind) { case 'ActorCreatedReport': typeElement.setAttribute('title', 'Actor created'); break; @@ -43,7 +43,7 @@ export class ReportableElementCreator { break; } - reportableElement.querySelector('.type i').textContent = reportable.Type; + reportableElement.querySelector('.type i').textContent = reportable.Kind; } #setupResult(reportableElement, reportable) { @@ -56,7 +56,7 @@ export class ReportableElementCreator { #setupPerformableType(reportableElement, reportable) { const performableTypeElement = reportableElement.querySelector('.performableType'); - if (reportable.PerformableType) performableTypeElement.querySelector('i').textContent = reportable.PerformableType; + if (reportable.Type) performableTypeElement.querySelector('i').textContent = reportable.Type; else performableTypeElement.remove() } diff --git a/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ReportWriter/ScenarioElementCreator.js b/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ReportWriter/ScenarioElementCreator.js index 4ac75003..3decae5a 100644 --- a/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ReportWriter/ScenarioElementCreator.js +++ b/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ReportWriter/ScenarioElementCreator.js @@ -17,7 +17,7 @@ export class ScenarioElementCreator { scenarioElement.querySelector('.scenarioName').textContent = scenario.scenario.Name; scenarioElement.querySelector('.scenarioName').addEventListener('click', ev => ev.currentTarget.parentElement.classList.toggle('collapsed')); - setContentOrRemove(scenarioElement, scenario.scenario, '.scenarioIdentifier', s => !s.WasIdentifierAutoGenerated, s => s.Identifier); + setContentOrRemove(scenarioElement, scenario.scenario, '.scenarioIdentifier', s => !s.IsGeneratedId, s => s.Id); const reportablesElement = scenarioElement.querySelector('.reportableList'); for (const reportable of scenario.performance.Reportables) { diff --git a/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ScenarioAggregator.js b/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ScenarioAggregator.js index e8ba2a19..3a08cac0 100644 --- a/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ScenarioAggregator.js +++ b/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ScenarioAggregator.js @@ -19,22 +19,23 @@ export class ScenarioAggregator { #getFeature(names) { return names.length > 1 ? names[names.length - 2] - : { Identifier: null, Name: "No Feature", WasIdentifierAutoGenerated: true }; + : { Id: null, Name: "No Feature", IsGeneratedId: true }; } #getScenario(names) { if (names.length > 0) return names[names.length - 1]; - return { Identifier: crypto.randomUUID(), Name: "No Scenario", WasIdentifierAutoGenerated: true }; + return { Id: crypto.randomUUID(), Name: "No Scenario", IsGeneratedId: true }; } #getFeatureContainer(accumulator, feature) { - if (feature.Identifier === null) return accumulator.noFeatureScenarios; - if (Object.hasOwn(accumulator.features, feature.Identifier)) return accumulator.features[feature.Identifier]; - return accumulator.features[feature.Identifier] = this.#createFeatureContainer(feature); + if (feature.Id === null) return accumulator.noFeatureScenarios; + if (Object.hasOwn(accumulator.features, feature.Id)) return accumulator.features[feature.Id]; + accumulator.features[feature.Id] = this.#createFeatureContainer(feature); + return accumulator.features[feature.Id]; } #createFeatureContainer(feature) { - return { feature: { Identifier: feature.Identifier, Name: feature.Name, WasIdentifierAutoGenerated: feature.WasIdentifierAutoGenerated }, scenarios: [] }; + return { feature: { Id: feature.Id, Name: feature.Name, IsGeneratedId: feature.IsGeneratedId }, scenarios: [] }; } } diff --git a/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ScenarioAggregator.spec.js b/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ScenarioAggregator.spec.js index 37849d40..b5ebcd94 100644 --- a/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ScenarioAggregator.spec.js +++ b/CSF.Screenplay.JsonToHtmlReport.Template/src/js/ScenarioAggregator.spec.js @@ -6,8 +6,8 @@ import { ScenarioAggregator } from './ScenarioAggregator'; test('getScenariosByFeature should return an object which aggregates two scenarios into a single feature', () => { const performances = [ - { NamingHierarchy: [{ Identifier: "feature-1", Name: "Feature 1", WasIdentifierAutoGenerated: false }, { Identifier: "scenario-1", Name: "Scenario 1", WasIdentifierAutoGenerated: false }] }, - { NamingHierarchy: [{ Identifier: "feature-1", Name: "Feature 1", WasIdentifierAutoGenerated: false }, { Identifier: "scenario-2", Name: "Scenario 2", WasIdentifierAutoGenerated: false }] } + { NamingHierarchy: [{ Id: "feature-1", Name: "Feature 1", IsGeneratedId: false }, { Id: "scenario-1", Name: "Scenario 1", IsGeneratedId: false }] }, + { NamingHierarchy: [{ Id: "feature-1", Name: "Feature 1", IsGeneratedId: false }, { Id: "scenario-2", Name: "Scenario 2", IsGeneratedId: false }] } ]; const sut = new ScenarioAggregator(performances); const result = sut.getScenariosByFeature(); @@ -15,24 +15,24 @@ test('getScenariosByFeature should return an object which aggregates two scenari features: { "feature-1": { feature: { - Identifier: "feature-1", + Id: "feature-1", Name: "Feature 1", - WasIdentifierAutoGenerated: false + IsGeneratedId: false }, scenarios: [ { scenario: { - Identifier: "scenario-1", + Id: "scenario-1", Name: "Scenario 1", - WasIdentifierAutoGenerated: false + IsGeneratedId: false }, performance: performances[0] }, { scenario: { - Identifier: "scenario-2", + Id: "scenario-2", Name: "Scenario 2", - WasIdentifierAutoGenerated: false + IsGeneratedId: false }, performance: performances[1] } @@ -45,8 +45,8 @@ test('getScenariosByFeature should return an object which aggregates two scenari test('getScenariosByFeature should return an object which correctly aggregates scenarios which belong to different features', () => { const performances = [ - { NamingHierarchy: [{ Identifier: "feature-1", Name: "Feature 1", WasIdentifierAutoGenerated: false }, { Identifier: "scenario-1", Name: "Scenario 1", WasIdentifierAutoGenerated: false }] }, - { NamingHierarchy: [{ Identifier: "feature-2", Name: "Feature 2", WasIdentifierAutoGenerated: false }, { Identifier: "scenario-2", Name: "Scenario 2", WasIdentifierAutoGenerated: false }] } + { NamingHierarchy: [{ Id: "feature-1", Name: "Feature 1", IsGeneratedId: false }, { Id: "scenario-1", Name: "Scenario 1", IsGeneratedId: false }] }, + { NamingHierarchy: [{ Id: "feature-2", Name: "Feature 2", IsGeneratedId: false }, { Id: "scenario-2", Name: "Scenario 2", IsGeneratedId: false }] } ]; const sut = new ScenarioAggregator(performances); const result = sut.getScenariosByFeature(); @@ -54,16 +54,16 @@ test('getScenariosByFeature should return an object which correctly aggregates s features: { "feature-1": { feature: { - Identifier: "feature-1", + Id: "feature-1", Name: "Feature 1", - WasIdentifierAutoGenerated: false + IsGeneratedId: false }, scenarios: [ { scenario: { - Identifier: "scenario-1", + Id: "scenario-1", Name: "Scenario 1", - WasIdentifierAutoGenerated: false + IsGeneratedId: false }, performance: performances[0] } @@ -71,16 +71,16 @@ test('getScenariosByFeature should return an object which correctly aggregates s }, "feature-2": { feature: { - Identifier: "feature-2", + Id: "feature-2", Name: "Feature 2", - WasIdentifierAutoGenerated: false + IsGeneratedId: false }, scenarios: [ { scenario: { - Identifier: "scenario-2", + Id: "scenario-2", Name: "Scenario 2", - WasIdentifierAutoGenerated: false + IsGeneratedId: false }, performance: performances[1] } @@ -93,7 +93,7 @@ test('getScenariosByFeature should return an object which correctly aggregates s test('getScenariosByFeature should place a no-feature scenario into the no-feature container', () => { const performances = [ - { NamingHierarchy: [{ Identifier: "scenario-1", Name: "Scenario 1", WasIdentifierAutoGenerated: false }] } + { NamingHierarchy: [{ Id: "scenario-1", Name: "Scenario 1", IsGeneratedId: false }] } ]; const sut = new ScenarioAggregator(performances); const result = sut.getScenariosByFeature(); @@ -103,9 +103,9 @@ test('getScenariosByFeature should place a no-feature scenario into the no-featu scenarios: [ { scenario: { - Identifier: "scenario-1", + Id: "scenario-1", Name: "Scenario 1", - WasIdentifierAutoGenerated: false + IsGeneratedId: false }, performance: performances[0] } @@ -114,7 +114,7 @@ test('getScenariosByFeature should place a no-feature scenario into the no-featu }); }); -test('getScenariosByFeature should invent a name and identifier for a scenario with no name', () => { +test('getScenariosByFeature should invent a name and Id for a scenario with no name', () => { const performances = [ { NamingHierarchy: [] } ]; @@ -126,9 +126,9 @@ test('getScenariosByFeature should invent a name and identifier for a scenario w scenarios: [ { scenario: { - Identifier: expect.any(String), + Id: expect.any(String), Name: "No Scenario", - WasIdentifierAutoGenerated: true + IsGeneratedId: true }, performance: performances[0] } @@ -142,9 +142,9 @@ test('getScenariosByFeature should choose the correct feature and scenario from const performances = [ { NamingHierarchy: [ - { Identifier: "CSF.Screenplay.Selenium.TestWebappSetupAndTeardown", Name: null, WasIdentifierAutoGenerated: false }, - { Identifier: "CSF.Screenplay.Selenium.Actions.ClearCookiesTests", Name: null, WasIdentifierAutoGenerated: false }, - { Identifier: "CSF.Screenplay.Selenium.Actions.ClearCookiesTests.ClearCookiesShouldClearCookies", Name: null, WasIdentifierAutoGenerated: false } + { Id: "CSF.Screenplay.Selenium.TestWebappSetupAndTeardown", Name: null, IsGeneratedId: false }, + { Id: "CSF.Screenplay.Selenium.Actions.ClearCookiesTests", Name: null, IsGeneratedId: false }, + { Id: "CSF.Screenplay.Selenium.Actions.ClearCookiesTests.ClearCookiesShouldClearCookies", Name: null, IsGeneratedId: false } ] } ]; @@ -154,16 +154,16 @@ test('getScenariosByFeature should choose the correct feature and scenario from features: { "CSF.Screenplay.Selenium.Actions.ClearCookiesTests": { feature: { - Identifier: "CSF.Screenplay.Selenium.Actions.ClearCookiesTests", + Id: "CSF.Screenplay.Selenium.Actions.ClearCookiesTests", Name: null, - WasIdentifierAutoGenerated: false + IsGeneratedId: false }, scenarios: [ { scenario: { - Identifier: "CSF.Screenplay.Selenium.Actions.ClearCookiesTests.ClearCookiesShouldClearCookies", + Id: "CSF.Screenplay.Selenium.Actions.ClearCookiesTests.ClearCookiesShouldClearCookies", Name: null, - WasIdentifierAutoGenerated: false + IsGeneratedId: false }, performance: performances[0] } diff --git a/CSF.Screenplay.JsonToHtmlReport/AssetEmbedder.cs b/CSF.Screenplay.JsonToHtmlReport/AssetEmbedder.cs index 6f4059e4..0573c015 100644 --- a/CSF.Screenplay.JsonToHtmlReport/AssetEmbedder.cs +++ b/CSF.Screenplay.JsonToHtmlReport/AssetEmbedder.cs @@ -68,9 +68,9 @@ static bool ShouldEmbed(PerformableAsset asset, IReadOnlyCollection applicableExtensions, bool ignoreExtension) { - if(string.IsNullOrWhiteSpace(asset.FilePath)) return false; + if(string.IsNullOrWhiteSpace(asset.Path)) return false; - var info = new FileInfo(asset.FilePath); + var info = new FileInfo(asset.Path); var fileSizeBytes = info.Length; var extension = info.Extension; @@ -81,15 +81,15 @@ static bool ShouldEmbed(PerformableAsset asset, #if !NETSTANDARD2_0 && !NET462 static async Task EmbedAssetIfApplicableAsync(PerformableAsset asset) { - var bytes = await File.ReadAllBytesAsync(asset.FilePath).ConfigureAwait(false); + var bytes = await File.ReadAllBytesAsync(asset.Path).ConfigureAwait(false); #else static Task EmbedAssetIfApplicableAsync(PerformableAsset asset) { - var bytes = File.ReadAllBytes(asset.FilePath); + var bytes = File.ReadAllBytes(asset.Path); #endif - asset.FileData = Convert.ToBase64String(bytes); - asset.FilePath = null; + asset.Data = Convert.ToBase64String(bytes); + asset.Path = null; #if NETSTANDARD2_0 || NET462 return Task.CompletedTask; #endif diff --git a/CSF.Screenplay/ReportModel/IdentifierAndNameModel.cs b/CSF.Screenplay/ReportModel/IdentifierAndNameModel.cs index 8fe155a2..8ae940ff 100644 --- a/CSF.Screenplay/ReportModel/IdentifierAndNameModel.cs +++ b/CSF.Screenplay/ReportModel/IdentifierAndNameModel.cs @@ -16,7 +16,7 @@ public class IdentifierAndNameModel /// /// Corresponds to the value . /// - public string Identifier { get; set; } + public string Id { get; set; } /// /// Corresponds to the value . @@ -26,6 +26,6 @@ public class IdentifierAndNameModel /// /// Corresponds to the value . /// - public bool WasIdentifierAutoGenerated { get; set; } + public bool IsGeneratedId { get; set; } } } \ No newline at end of file diff --git a/CSF.Screenplay/ReportModel/PerformableAsset.cs b/CSF.Screenplay/ReportModel/PerformableAsset.cs index b1a321cd..4532c7f2 100644 --- a/CSF.Screenplay/ReportModel/PerformableAsset.cs +++ b/CSF.Screenplay/ReportModel/PerformableAsset.cs @@ -12,12 +12,12 @@ namespace CSF.Screenplay.ReportModel /// down to the implementation. /// /// - /// Every asset has one or two properties in common, the and optionally . + /// Every asset has one or two properties in common, the and optionally . /// The data for the asset file is then described by one of two ways: /// /// - /// The content of the asset is located on disk at a path indicated by - /// The content of the asset is embedded within this model as base64-encoded text, within + /// The content of the asset is located on disk at a path indicated by + /// The content of the asset is embedded within this model as base64-encoded text, within /// /// /// Typically when reports are first created, for expedience, assets are recorded to disk as files. @@ -34,23 +34,23 @@ public class PerformableAsset /// /// Gets or sets a full/absolute path to the asset file. /// - public string FilePath { get; set; } + public string Path { get; set; } /// /// Gets or sets base64-encoded data which contains the data for the asset. /// - public string FileData { get; set; } + public string Data { get; set; } /// /// Gets or sets the name of the asset file, including its extension. /// - public string FileName { get; set; } + public string Name { get; set; } /// /// Gets or sets an optional human-readable summary of what this asset represents. This should be one sentence at most, suitable /// for display in a UI tool-tip. /// - public string FileSummary { get; set; } + public string Summary { get; set; } } } \ No newline at end of file diff --git a/CSF.Screenplay/ReportModel/PerformableReport.cs b/CSF.Screenplay/ReportModel/PerformableReport.cs index 6091a65e..5df56728 100644 --- a/CSF.Screenplay/ReportModel/PerformableReport.cs +++ b/CSF.Screenplay/ReportModel/PerformableReport.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Text.Json.Serialization; namespace CSF.Screenplay.ReportModel { @@ -17,11 +18,26 @@ public class PerformableReport : ReportableModelBase { List assets = new List(); List reportables = new List(); + string phase; /// - /// Gets or sets the of the to which this report model relates. + /// Gets or sets type information for the to which this report model relates. /// - public string PerformableType { get; set; } + /// + /// + /// In many cases this is equal to the of the performable class. + /// However, it does not have to be. This is a human-readable value which is intended to convey useful information to a reader (who + /// understands what a .NET type is) about the performable type. + /// + /// + /// Consider a performable type which is an adapter class, that wraps a more specific performable. The full name of the performable type itself + /// might not be very useful, as it would only indicate a general-use adapter type. This becomes even less useful when the adapter type is generic. + /// Performable types which are general-use adapters, which would 'hide' a more specific (and useful) performable type may implement + /// . Performable types which derive from the custom type name interface populate this value with the value retrieved from + /// instead of their type's full name.. + /// + /// + public string Type { get; set; } /// /// Corresponds to the to which the current reportable is part. @@ -29,11 +45,19 @@ public class PerformableReport : ReportableModelBase /// /// /// This property contains the string representation of that performance phase. - /// It is quite rare for this property to be unset (IE: ), typically it is only unset for the - /// initial creation/setup of Actors at the beginning of a performance. + /// This property should always have a non- value at the top-level of a performance. + /// At deeper levels, it is acceptable for this property to be null, since all consumed performables are presumed to inherit the performance + /// phase of their consumer. + /// + /// + /// This property normalises null, empty or whitespace-only values to , so that this property may be skipped when it is empty. /// /// - public string PerformancePhase { get; set; } + public string Phase + { + get => phase; + set => phase = string.IsNullOrWhiteSpace(value) ? null : value; + } /// /// Gets or sets the relative time at which this performable ended/finished. @@ -93,32 +117,53 @@ public class PerformableReport : ReportableModelBase public string Exception { get; set; } /// - /// Gets a value which indicates whether or not the is one which was originally thrown from a consumed performable. + /// Gets a value which indicates whether or not the is one which was originally thrown from a consumed performable, 'bubbling' up the call stack. /// /// /// /// If is then the value of this property is meaningless and undefined. /// If the exception is not null then - if this property is set to then it means that exception which /// is recorded for this performable was originally thrown from a performable which was consumed by the current one. - /// In other words, it indicates whether or not the reason for the current performable's error was because a consumed/child - /// performable encountered an error. + /// + /// + /// When this is , it means that the error did not originate within the current performable. The current performable + /// has failed only because a consumed/child performable encountered an error, and that error is 'bubbling' up the call stack, failing each consuming + /// performable, until it reaches a catch block or the performance ends. /// /// /// If, on the other hand, is not and this property value is /// then it indicates that the current performable is the original source of the error. /// /// - public bool ExceptionIsFromConsumedPerformable { get; set; } + public bool ExceptionIsBubbling { get; set; } /// /// Gets or sets a collection of the assets which were recorded by the current performable. /// + [JsonIgnore] public List Assets { get => assets; set => assets = value ?? throw new ArgumentNullException(nameof(value)); } + /// + /// Gets or sets a representation of which is designed for JSON serialization. + /// + /// + /// + /// Notably, this property getter will return if is empty. + /// This is desirable for serialization, because it allows us to ignore/skip this property when it's empty. + /// For general use as a developer, use instead. + /// + /// + [JsonPropertyName(nameof(Assets))] + public List SerializableAssets + { + get => Assets.Count > 0 ? Assets : null; + set => Assets = value ?? new List(); + } + /// /// Gets or sets a collection of the reportable items which have been composed by the current performable. /// @@ -130,10 +175,28 @@ public List Assets /// That structure could be deeply nested. /// /// + [JsonIgnore] public List Reportables { get => reportables; set => reportables = value ?? throw new ArgumentNullException(nameof(value)); } + + /// + /// Gets or sets a representation of which is designed for JSON serialization. + /// + /// + /// + /// Notably, this property getter will return if is empty. + /// This is desirable for serialization, because it allows us to ignore/skip this property when it's empty. + /// For general use as a developer, use instead. + /// + /// + [JsonPropertyName(nameof(Reportables))] + public List SerializableReportables + { + get => Reportables.Count > 0 ? Reportables : null; + set => Reportables = value ?? new List(); + } } } \ No newline at end of file diff --git a/CSF.Screenplay/ReportModel/ReportMetadata.cs b/CSF.Screenplay/ReportModel/ReportMetadata.cs index eebbe0ea..ab72e90d 100644 --- a/CSF.Screenplay/ReportModel/ReportMetadata.cs +++ b/CSF.Screenplay/ReportModel/ReportMetadata.cs @@ -28,6 +28,6 @@ public class ReportMetadata /// It may be used to assist parsing logic determine whether or not it is reading a compatible report file. /// /// - public string ReportFormatVersion { get; set; } = reportFormatVersion; + public string ReportVersion { get; set; } = reportFormatVersion; } } \ No newline at end of file diff --git a/CSF.Screenplay/ReportModel/ReportableModelBase.cs b/CSF.Screenplay/ReportModel/ReportableModelBase.cs index c1bb234c..0441bc9f 100644 --- a/CSF.Screenplay/ReportModel/ReportableModelBase.cs +++ b/CSF.Screenplay/ReportModel/ReportableModelBase.cs @@ -11,7 +11,7 @@ namespace CSF.Screenplay.ReportModel /// This base model has subclasses for each of the specific types of event which may be reported-upon. /// /// - [JsonPolymorphic(TypeDiscriminatorPropertyName = "Type")] + [JsonPolymorphic(TypeDiscriminatorPropertyName = "Kind")] [JsonDerivedType(typeof(ActorCreatedReport), nameof(ActorCreatedReport))] [JsonDerivedType(typeof(ActorGainedAbilityReport), nameof(ActorGainedAbilityReport))] [JsonDerivedType(typeof(ActorSpotlitReport), nameof(ActorSpotlitReport))] @@ -23,16 +23,16 @@ public abstract class ReportableModelBase /// Gets or sets the human-readable text of the report. /// public string Report { get; set; } - + /// - /// Gets or sets the name of the who is associated with this report. + /// Gets or sets the name of the who is associated with this report. /// /// /// /// Almost all reportables involve an actor, it is rare for this value to be unset (IE: ). /// /// - public string ActorName { get; set; } + public string Actor { get; set; } /// /// Gets or sets the relative time at which this reportable event occurred. diff --git a/CSF.Screenplay/Reporting/JsonScreenplayReporter.cs b/CSF.Screenplay/Reporting/JsonScreenplayReporter.cs index 1ba28d9d..8afb8d45 100644 --- a/CSF.Screenplay/Reporting/JsonScreenplayReporter.cs +++ b/CSF.Screenplay/Reporting/JsonScreenplayReporter.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Text.Json; +using System.Text.Json.Serialization; using CSF.Screenplay.Actors; using CSF.Screenplay.Performances; using CSF.Screenplay.ReportModel; @@ -40,6 +41,11 @@ namespace CSF.Screenplay.Reporting /// public sealed class JsonScreenplayReporter : IReporter { + static readonly JsonSerializerOptions jsonOptions = new JsonSerializerOptions + { + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault + }; + readonly ScreenplayReportBuilder builder; readonly IMeasuresTime reportTimer; readonly Utf8JsonWriter jsonWriter; @@ -154,7 +160,7 @@ void OnPerformanceFinished(object sender, PerformanceFinishedEventArgs e) var report = builder.EndPerformanceAndGetReport(e.PerformanceIdentity, e.Success); lock(syncRoot) { - JsonSerializer.Serialize(jsonWriter, report); + JsonSerializer.Serialize(jsonWriter, report, jsonOptions); jsonWriter.Flush(); } } diff --git a/CSF.Screenplay/Reporting/PerformanceReportBuilder.cs b/CSF.Screenplay/Reporting/PerformanceReportBuilder.cs index 99c3b6cb..901830f0 100644 --- a/CSF.Screenplay/Reporting/PerformanceReportBuilder.cs +++ b/CSF.Screenplay/Reporting/PerformanceReportBuilder.cs @@ -83,7 +83,7 @@ public void ActorCreated(Actor actor) { NewPerformableList.Add(new ActorCreatedReport { - ActorName = actor.Name, + Actor = actor.Name, Report = string.Format(ReportStrings.ActorCreatedFormat, actor.Name), Started = reportTimer.GetCurrentTime(), }); @@ -102,7 +102,7 @@ public void ActorGainedAbility(Actor actor, object ability) NewPerformableList.Add(new ActorGainedAbilityReport { - ActorName = actor.Name, + Actor = actor.Name, Report = reportText, Started = reportTimer.GetCurrentTime(), }); @@ -121,7 +121,7 @@ public void ActorSpotlit(Actor actor) { NewPerformableList.Add(new ActorSpotlitReport { - ActorName = actor.Name, + Actor = actor.Name, Report = string.Format(ReportStrings.ActorSpotlitFormat, actor.Name), Started = reportTimer.GetCurrentTime(), }); @@ -174,11 +174,11 @@ public void BeginPerformable(object performable, Actor actor, string performance { var performableReport = new PerformableReport { - PerformableType = performable is IHasCustomTypeName customName + Type = performable is IHasCustomTypeName customName ? customName.GetHumanReadableTypeName() : performable.GetType().FullName, - ActorName = actor.Name, - PerformancePhase = performancePhase, + Actor = actor.Name, + Phase = performancePhase, Started = reportTimer.GetCurrentTime(), }; @@ -201,9 +201,9 @@ public void RecordAssetForCurrentPerformable(string assetPath, string assetSumma var fileName = Path.GetFileName(assetPath); var asset = new PerformableAsset { - FilePath = assetPath, - FileSummary = assetSummary, - FileName = fileName, + Path = assetPath, + Summary = assetSummary, + Name = fileName, ContentType = contentTypeProvider.GetContentType(fileName), }; CurrentPerformable.Assets.Add(asset); @@ -264,7 +264,7 @@ public void EndPerformable(object performable, Actor actor) public void RecordFailureForCurrentPerformable(Exception exception, object performable, Actor actor) { CurrentPerformable.Exception = exception.ToString(); - CurrentPerformable.ExceptionIsFromConsumedPerformable = exception is PerformableException; + CurrentPerformable.ExceptionIsBubbling = exception is PerformableException; EndPerformable(performable, actor); } diff --git a/CSF.Screenplay/Reporting/ScreenplayReportBuilder.cs b/CSF.Screenplay/Reporting/ScreenplayReportBuilder.cs index c19fe23c..c7291406 100644 --- a/CSF.Screenplay/Reporting/ScreenplayReportBuilder.cs +++ b/CSF.Screenplay/Reporting/ScreenplayReportBuilder.cs @@ -51,7 +51,7 @@ public class ScreenplayReportBuilder public void BeginPerformance(Guid performanceIdentifier, IReadOnlyList namingHierarchy) { var mappedNamingHierarchy = namingHierarchy - .Select(x => new IdentifierAndNameModel { Identifier = x.Identifier, Name = x.Name, WasIdentifierAutoGenerated = x.WasIdentifierAutoGenerated }) + .Select(x => new IdentifierAndNameModel { Id = x.Identifier, Name = x.Name, IsGeneratedId = x.WasIdentifierAutoGenerated }) .ToList(); performanceReports.TryAdd(performanceIdentifier, performanceBuilderFactory(mappedNamingHierarchy, reportTimer)); } diff --git a/Tests/CSF.Screenplay.Tests/JsonToHtmlReport/AssetEmbedderTests.cs b/Tests/CSF.Screenplay.Tests/JsonToHtmlReport/AssetEmbedderTests.cs index 69de2b11..357a3231 100644 --- a/Tests/CSF.Screenplay.Tests/JsonToHtmlReport/AssetEmbedderTests.cs +++ b/Tests/CSF.Screenplay.Tests/JsonToHtmlReport/AssetEmbedderTests.cs @@ -16,7 +16,7 @@ public async Task EmbedReportAssetsAsyncShouldEmbedTwoEligibleAssets(AssetEmbedd { await sut.EmbedReportAssetsAsync(report, new () { EmbeddedFileExtensions = "png,jpeg", EmbeddedFileSizeThresholdKb = 50 }); var performable = report.Performances.First().Reportables.OfType().First(); - Assert.That(performable.Assets, Has.All.Matches(a => a is { FilePath: null, FileData: not null }), "Assets have been embedded"); + Assert.That(performable.Assets, Has.All.Matches(a => a is { Path: null, Data: not null }), "Assets have been embedded"); } [Test, AutoMoqData] @@ -27,10 +27,10 @@ public async Task EmbedReportAssetsAsyncShouldNotEmbedAnAssetOfAnUnsupportedType using var scope = Assert.EnterMultipleScope(); Assert.That(performable.Assets, - Has.One.Matches(a => a is { FileName: SampleAssetsCustomization.Asset2Filename, FileData: not null }), + Has.One.Matches(a => a is { Name: SampleAssetsCustomization.Asset2Filename, Data: not null }), "JPEG asset has been embedded"); Assert.That(performable.Assets, - Has.One.Matches(a => a is { FileName: SampleAssetsCustomization.Asset1Filename, FileData: null }), + Has.One.Matches(a => a is { Name: SampleAssetsCustomization.Asset1Filename, Data: null }), "PNG asset has not been embedded"); } @@ -39,7 +39,7 @@ public async Task EmbedReportAssetsAsyncShouldEmbedAllAssetsIfFileExtensionIsAst { await sut.EmbedReportAssetsAsync(report, new () { EmbeddedFileExtensions = "*", EmbeddedFileSizeThresholdKb = 50 }); var performable = report.Performances.First().Reportables.OfType().First(); - Assert.That(performable.Assets, Has.All.Matches(a => a is { FilePath: null, FileData: not null }), "Assets have been embedded"); + Assert.That(performable.Assets, Has.All.Matches(a => a is { Path: null, Data: not null }), "Assets have been embedded"); } [Test, AutoMoqData] @@ -50,10 +50,10 @@ public async Task EmbedReportAssetsAsyncShouldNotEmbedAnAssetWhichIsTooLarge(Ass using var scope = Assert.EnterMultipleScope(); Assert.That(performable.Assets, - Has.One.Matches(a => a is { FileName: SampleAssetsCustomization.Asset2Filename, FileData: null }), + Has.One.Matches(a => a is { Name: SampleAssetsCustomization.Asset2Filename, Data: null }), "JPEG asset has not been embedded"); Assert.That(performable.Assets, - Has.One.Matches(a => a is { FileName: SampleAssetsCustomization.Asset1Filename, FileData: not null }), + Has.One.Matches(a => a is { Name: SampleAssetsCustomization.Asset1Filename, Data: not null }), "PNG asset has been embedded"); } @@ -64,10 +64,10 @@ public async Task EmbedReportAssetsAsyncShouldUseCorrectBase64(AssetEmbedder sut var performable = report.Performances.First().Reportables.OfType().First(); using var scope = Assert.EnterMultipleScope(); - var asset1Data = performable.Assets.FirstOrDefault(x => x.FileName == SampleAssetsCustomization.Asset1Filename)?.FileData; + var asset1Data = performable.Assets.FirstOrDefault(x => x.Name == SampleAssetsCustomization.Asset1Filename)?.Data; Assert.That(asset1Data, Is.EqualTo(asset1Base64), "PNG asset encoded correctly"); - var asset2Data = performable.Assets.FirstOrDefault(x => x.FileName == SampleAssetsCustomization.Asset2Filename)?.FileData; + var asset2Data = performable.Assets.FirstOrDefault(x => x.Name == SampleAssetsCustomization.Asset2Filename)?.Data; Assert.That(asset2Data, Is.EqualTo(asset2Base64), "JPEG asset encoded correctly"); } diff --git a/Tests/CSF.Screenplay.Tests/Reporting/PerformanceReportBuilderTests.cs b/Tests/CSF.Screenplay.Tests/Reporting/PerformanceReportBuilderTests.cs index fc716841..21a34c26 100644 --- a/Tests/CSF.Screenplay.Tests/Reporting/PerformanceReportBuilderTests.cs +++ b/Tests/CSF.Screenplay.Tests/Reporting/PerformanceReportBuilderTests.cs @@ -35,7 +35,7 @@ public void ActorCreatedShouldAddAnActorCreatedReportableWithTheCorrectNameAndRe { sut.ActorCreated(actor); var report = sut.GetReport(outcome); - Assert.That(report.Reportables, Has.One.Matches(x => x.ActorName == "Joe" && x.Report == "Joe joined the performance")); + Assert.That(report.Reportables, Has.One.Matches(x => x.Actor == "Joe" && x.Report == "Joe joined the performance")); } [Test, AutoMoqData] @@ -48,7 +48,7 @@ public void ActorGainedAbilityShouldAddAGainedAbilityReportableWithAnAbilityGene Mock.Get(ability).Setup(x => x.GetReportFragment(actor, formatter)).Returns(new ReportFragment("Original", "Formatted", Array.Empty())); sut.ActorGainedAbility(actor, ability); var report = sut.GetReport(outcome); - Assert.That(report.Reportables, Has.One.Matches(x => x.ActorName == "Joe" && x.Report == "Formatted")); + Assert.That(report.Reportables, Has.One.Matches(x => x.Actor == "Joe" && x.Report == "Formatted")); } [Test, AutoMoqData] @@ -63,7 +63,7 @@ public void ActorGainedAbilityShouldAddAGainedAbilityReportableWithAGeneratedRep Mock.Get(valueFormatter).Setup(x => x.FormatForReport(ability)).Returns("Ability Name"); sut.ActorGainedAbility(actor, ability); var report = sut.GetReport(outcome); - Assert.That(report.Reportables, Has.One.Matches(x => x.ActorName == "Joe" && x.Report == "Joe is able to Ability Name")); + Assert.That(report.Reportables, Has.One.Matches(x => x.Actor == "Joe" && x.Report == "Joe is able to Ability Name")); } [Test, AutoMoqData] @@ -73,7 +73,7 @@ public void ActorSpotlitShouldAddASpotlitReportableWithTheCorrectReportText(Perf { sut.ActorSpotlit(actor); var report = sut.GetReport(outcome); - Assert.That(report.Reportables, Has.One.Matches(x => x.ActorName == "Joe" && x.Report == "Joe was put into the spotlight")); + Assert.That(report.Reportables, Has.One.Matches(x => x.Actor == "Joe" && x.Report == "Joe was put into the spotlight")); } [Test,AutoMoqData] @@ -82,7 +82,7 @@ public void SpotlightTurnedOffShouldAddASpotlightOffReportableWithTheCorrectRepo { sut.SpotlightTurnedOff(); var report = sut.GetReport(outcome); - Assert.That(report.Reportables, Has.One.Matches(x => x.ActorName == null && x.Report == "The spotlight was turned off")); + Assert.That(report.Reportables, Has.One.Matches(x => x.Actor == null && x.Report == "The spotlight was turned off")); } [Test, AutoMoqData] @@ -98,10 +98,10 @@ public void BeginAndEndPerformableShouldAddAPerformableReportableWithCorrectValu sut.EndPerformable(performable, actor); var report = sut.GetReport(outcome); Assert.That(report.Reportables, - Has.One.Matches(x => x.ActorName == "Joe" + Has.One.Matches(x => x.Actor == "Joe" && x.Report == "Formatted" - && x.PerformancePhase == performancePhase - && x.PerformableType == "CSF.Screenplay.Performables.StartTheStopwatch")); + && x.Phase == performancePhase + && x.Type == "CSF.Screenplay.Performables.StartTheStopwatch")); } [Test, AutoMoqData] @@ -128,7 +128,7 @@ public void BeginAndEndPerformableShouldBeAbleToCreateAHierarchyOfPerformableRep var taskReport = report.Reportables.OfType().Single(); Assert.That(taskReport.Reportables, Has.Count.EqualTo(2), "Two child reports should be present"); - Assert.That(taskReport.Reportables.OfType().Select(x => x.PerformableType), + Assert.That(taskReport.Reportables.OfType().Select(x => x.Type), Is.EqualTo(new[] { "CSF.Screenplay.Performables.StartTheStopwatch", "CSF.Screenplay.Performables.StopTheStopwatch" }), "The child reports should be of the correct performable types"); } @@ -163,7 +163,7 @@ public void RecordAssetForCurrentPerformableShouldAddAnAssetToTheReportable(Perf var report = sut.GetReport(outcome); Assert.That(report.Reportables.OfType().Single().Assets, - Has.One.Matches(x => x.FilePath == assetFilename && x.FileSummary == assetSummary)); + Has.One.Matches(x => x.Path == assetFilename && x.Summary == assetSummary)); } [Test, AutoMoqData] @@ -198,7 +198,7 @@ public void RecordFailureForCurrentPerformableShouldAddTheExceptionStringToTheRe sut.RecordFailureForCurrentPerformable(new Exception("An error occurred"), performable, actor); var report = sut.GetReport(outcome); Assert.That(report.Reportables, - Has.One.Matches(x => x.Exception.Contains("An error occurred") && x.ExceptionIsFromConsumedPerformable == false)); + Has.One.Matches(x => x.Exception.Contains("An error occurred") && x.ExceptionIsBubbling == false)); } [Test, AutoMoqData] @@ -241,7 +241,7 @@ public void RecordFailureForCurrentPerformableShouldSetExceptionIsFromConsumedPe sut.RecordFailureForCurrentPerformable(new PerformableException("An error occurred"), performable, actor); var report = sut.GetReport(outcome); Assert.That(report.Reportables, - Has.One.Matches(x => x.Exception.Contains("An error occurred") && x.ExceptionIsFromConsumedPerformable == true)); + Has.One.Matches(x => x.Exception.Contains("An error occurred") && x.ExceptionIsBubbling == true)); } public class TaskPerformable : IPerformable, ICanReport diff --git a/Tests/CSF.Screenplay.Tests/Reporting/ScreenplayReportSerializerTests.cs b/Tests/CSF.Screenplay.Tests/Reporting/ScreenplayReportSerializerTests.cs index 83101f65..5e14ede1 100644 --- a/Tests/CSF.Screenplay.Tests/Reporting/ScreenplayReportSerializerTests.cs +++ b/Tests/CSF.Screenplay.Tests/Reporting/ScreenplayReportSerializerTests.cs @@ -8,28 +8,28 @@ namespace CSF.Screenplay.Reporting; [TestFixture, Parallelizable] public class ScreenplayReportSerializerTests { - const string reportJson = @"{""Metadata"": {""Timestamp"": ""2021-01-01T00:00:00Z"",""ReportFormatVersion"": ""2.0.0""}, + const string reportJson = @"{""Metadata"": {""Timestamp"": ""2021-01-01T00:00:00Z"",""ReportVersion"": ""2.0.0""}, ""Performances"": [ { ""NamingHierarchy"": [ - {""Identifier"": ""1"",""Name"": ""First""}, - {""Identifier"": ""2"",""Name"": ""Second""} + {""Id"": ""1"",""Name"": ""First""}, + {""Id"": ""2"",""Name"": ""Second""} ], ""Reportables"": [ { - ""Type"": ""PerformableReport"", + ""Kind"": ""PerformableReport"", ""Report"": ""This is a report string"", - ""ActorName"": ""Joe"", - ""PerformableType"": ""APerformableType"", - ""PerformancePhase"": ""Given"", + ""Actor"": ""Joe"", + ""Type"": ""APerformableType"", + ""Phase"": ""Given"", ""Result"": ""A result"", ""HasResult"": true, - ""Assets"": [{""FilePath"": ""../a/file/path.txt"",""FileSummary"": ""This is a test asset""}], + ""Assets"": [{""Path"": ""../a/file/path.txt"",""Summary"": ""This is a test asset""}], ""Reportables"": [ { - ""Type"": ""ActorCreatedReport"", + ""Kind"": ""ActorCreatedReport"", ""Report"": ""This is a nested report string"", - ""ActorName"": ""Joe"" + ""Actor"": ""Joe"" } ] } @@ -46,10 +46,10 @@ public void DeserializeAsyncShouldThrowIfStreamIsNull(ScreenplayReportSerializer [Test, AutoMoqData] public async Task DeserializeAsyncShouldDeserializeAStream(ScreenplayReportSerializer sut) { - var bytes = Encoding.UTF8.GetBytes(@"{""Metadata"": { ""ReportFormatVersion"": ""foo bar"" }}"); + var bytes = Encoding.UTF8.GetBytes(@"{""Metadata"": { ""ReportVersion"": ""foo bar"" }}"); var stream = new MemoryStream(bytes); var report = await sut.DeserializeAsync(stream); - Assert.That(report.Metadata.ReportFormatVersion, Is.EqualTo("foo bar")); + Assert.That(report.Metadata.ReportVersion, Is.EqualTo("foo bar")); } [Test, AutoMoqData] @@ -61,7 +61,7 @@ public async Task DeserializeAsyncShouldReturnAScreenplayReport(ScreenplayReport using var scope = Assert.EnterMultipleScope(); Assert.That(result, Is.Not.Null, "The deserialized report should not be null."); Assert.That(result.Metadata.Timestamp, Is.EqualTo(new DateTimeOffset(2021, 1, 1, 0, 0, 0, TimeSpan.Zero)), "The timestamp should be correct."); - Assert.That(result.Metadata.ReportFormatVersion, Is.EqualTo("2.0.0"), "The report format version should be correct."); + Assert.That(result.Metadata.ReportVersion, Is.EqualTo("2.0.0"), "The report format version should be correct."); Assert.That(result.Performances, Has.Count.EqualTo(1), "There should be one performance."); var firstPerformance = result.Performances.Single(); @@ -71,17 +71,17 @@ public async Task DeserializeAsyncShouldReturnAScreenplayReport(ScreenplayReport var firstReportable = firstPerformance.Reportables.Single(); Assert.That(firstReportable.Report, Is.EqualTo("This is a report string"), "The report string should be correct."); - Assert.That(firstReportable.ActorName, Is.EqualTo("Joe"), "The actor name should be correct."); + Assert.That(firstReportable.Actor, Is.EqualTo("Joe"), "The actor name should be correct."); Assert.That(firstReportable, Is.InstanceOf(), "The reportable should be a PerformableReport."); var performableReport = (PerformableReport) firstReportable; - Assert.That(performableReport.PerformableType, Is.EqualTo("APerformableType"), "The performable type should be correct."); - Assert.That(performableReport.PerformancePhase, Is.EqualTo("Given"), "The performance phase should be correct."); + Assert.That(performableReport.Type, Is.EqualTo("APerformableType"), "The performable type should be correct."); + Assert.That(performableReport.Phase, Is.EqualTo("Given"), "The performance phase should be correct."); Assert.That(performableReport.Result, Is.EqualTo("A result"), "The result should be correct."); Assert.That(performableReport.HasResult, Is.True, "The HasResult flag should be correct."); Assert.That(performableReport.Assets, Has.Count.EqualTo(1), "There should be one asset."); - Assert.That(performableReport.Assets.Single().FilePath, Is.EqualTo("../a/file/path.txt"), "The asset file path should be correct."); - Assert.That(performableReport.Assets.Single().FileSummary, Is.EqualTo("This is a test asset"), "The asset file summary should be correct."); + Assert.That(performableReport.Assets.Single().Path, Is.EqualTo("../a/file/path.txt"), "The asset file path should be correct."); + Assert.That(performableReport.Assets.Single().Summary, Is.EqualTo("This is a test asset"), "The asset file summary should be correct."); Assert.That(performableReport.Reportables, Has.Count.EqualTo(1), "There should be one nested reportable."); } @@ -94,10 +94,10 @@ public void SerializeAsyncShouldThrowIfReportIsNull(ScreenplayReportSerializer s [Test, AutoMoqData] public async Task SerializeAsyncShouldSerializeToAStream(ScreenplayReportSerializer sut) { - var report = new ScreenplayReport() { Metadata = new () { ReportFormatVersion = "foo bar", Timestamp = DateTimeOffset.UtcNow } }; + var report = new ScreenplayReport() { Metadata = new () { ReportVersion = "foo bar", Timestamp = DateTimeOffset.UtcNow } }; var stream = await sut.SerializeAsync(report); using var reader = new StreamReader(stream); var content = await reader.ReadToEndAsync(); - Assert.That(content, Does.Match(@"^\{""Metadata"":\{""Timestamp"":""[\d-]{10}T[\d:.]{10,16}\+00:00"",""ReportFormatVersion"":""foo bar""\},""Performances"":\[\]\}$")); + Assert.That(content, Does.Match(@"^\{""Metadata"":\{""Timestamp"":""[\d-]{10}T[\d:.]{10,16}\+00:00"",""ReportVersion"":""foo bar""\},""Performances"":\[\]\}$")); } } \ No newline at end of file diff --git a/Tests/CSF.Screenplay.Tests/SampleAssetsAttribute.cs b/Tests/CSF.Screenplay.Tests/SampleAssetsAttribute.cs index f49e2b2a..08e7c316 100644 --- a/Tests/CSF.Screenplay.Tests/SampleAssetsAttribute.cs +++ b/Tests/CSF.Screenplay.Tests/SampleAssetsAttribute.cs @@ -32,13 +32,13 @@ public void Customize(IFixture fixture) Assets = [ new () { ContentType = MimeTypes.GetMimeType(Asset1Filename), - FileName = Asset1Filename, - FilePath = Path.Combine(Environment.CurrentDirectory, Asset1Filename) + Name = Asset1Filename, + Path = Path.Combine(Environment.CurrentDirectory, Asset1Filename) }, new () { ContentType = MimeTypes.GetMimeType(Asset2Filename), - FileName = Asset2Filename, - FilePath = Path.Combine(Environment.CurrentDirectory, Asset2Filename) + Name = Asset2Filename, + Path = Path.Combine(Environment.CurrentDirectory, Asset2Filename) }, ] }