diff --git a/CHANGELOG.md b/CHANGELOG.md index a94fa9b9..35c79d9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Added +- [.Net] Added possibility to customize resources for MessagesToHtmlWriter ([#400](https://github.com/cucumber/html-formatter/pull/400)) + ### Changed - Upgrade `react-components` to [23.2.0](https://github.com/cucumber/react-components/releases/tag/v23.2.0) diff --git a/dotnet/Cucumber.HtmlFormatter/DefaultResourceProvider.cs b/dotnet/Cucumber.HtmlFormatter/DefaultResourceProvider.cs new file mode 100644 index 00000000..4fe90e87 --- /dev/null +++ b/dotnet/Cucumber.HtmlFormatter/DefaultResourceProvider.cs @@ -0,0 +1,65 @@ +using System.Reflection; + +namespace Cucumber.HtmlFormatter; + +/// +/// Default implementation of IResourceProvider +/// +public class DefaultResourceProvider : IResourceProvider +{ + private const string TEMPLATE_RESOURCE_NAME = "index.mustache.html"; + private const string CSS_RESOURCE_NAME = "main.css"; + private const string JAVASCRIPT_RESOURCE_NAME = "main.js"; + private readonly Assembly _assembly; + private readonly string _resourceNamespace; + + public DefaultResourceProvider() + { + _assembly = typeof(MessagesToHtmlWriter).Assembly; + _resourceNamespace = "Cucumber.HtmlFormatter.Resources."; + } + + /// + /// Constructor with custom assembly and namespace + /// + /// The assembly to load resources from + /// The namespace prefix for resources + public DefaultResourceProvider(Assembly assembly, string resourceNamespace) + { + _assembly = assembly; + _resourceNamespace = resourceNamespace; + } + + /// + public string GetTemplateResource() + { + return GetResource(TEMPLATE_RESOURCE_NAME); + } + + /// + public string GetCssResource() + { + return GetResource(CSS_RESOURCE_NAME); + } + + /// + public string GetJavaScriptResource() + { + return GetResource(JAVASCRIPT_RESOURCE_NAME); + } + + /// + /// Gets a resource from the assembly + /// + /// The resource name + /// The resource content + private string GetResource(string name) + { + var resourceStream = _assembly.GetManifestResourceStream(_resourceNamespace + name); + if (resourceStream == null) + throw new InvalidOperationException($"Resource '{name}' not found in assembly '{_assembly.FullName}'"); + + using var reader = new StreamReader(resourceStream); + return reader.ReadToEnd(); + } +} \ No newline at end of file diff --git a/dotnet/Cucumber.HtmlFormatter/IResourceProvider.cs b/dotnet/Cucumber.HtmlFormatter/IResourceProvider.cs new file mode 100644 index 00000000..ce9f24ad --- /dev/null +++ b/dotnet/Cucumber.HtmlFormatter/IResourceProvider.cs @@ -0,0 +1,26 @@ +namespace Cucumber.HtmlFormatter; + +/// +/// Interface for providing resources to the HTML formatter. +/// This is an experimental API for allowing customizations, will be replaced by a more flexible solution in an upcoming release. +/// +public interface IResourceProvider +{ + /// + /// Gets the HTML template + /// + /// The HTML template + string GetTemplateResource(); + + /// + /// Gets the CSS resource + /// + /// The CSS resource + string GetCssResource(); + + /// + /// Gets the JavaScript resource + /// + /// The JavaScript resource + string GetJavaScriptResource(); +} \ No newline at end of file diff --git a/dotnet/Cucumber.HtmlFormatter/MessagesToHtmlWriter.cs b/dotnet/Cucumber.HtmlFormatter/MessagesToHtmlWriter.cs index 7c460b22..d2629d2d 100644 --- a/dotnet/Cucumber.HtmlFormatter/MessagesToHtmlWriter.cs +++ b/dotnet/Cucumber.HtmlFormatter/MessagesToHtmlWriter.cs @@ -9,6 +9,7 @@ public class MessagesToHtmlWriter : IDisposable private readonly Action _streamSerializer; private readonly string _template; private readonly JsonInHtmlWriter _jsonInHtmlWriter; + private readonly IResourceProvider _resourceProvider; private bool _streamClosed = false; private bool _preMessageWritten = false; private bool _firstMessageWritten = false; @@ -19,30 +20,36 @@ public class MessagesToHtmlWriter : IDisposable public MessagesToHtmlWriter(Stream stream, Action streamSerializer) : this(new StreamWriter(stream), streamSerializer) { } - public MessagesToHtmlWriter(Stream stream, Func asyncStreamSerializer) : this(new StreamWriter(stream), asyncStreamSerializer) { } + + public MessagesToHtmlWriter(Stream stream, Func asyncStreamSerializer, IResourceProvider? resourceProvider = null) + : this(new StreamWriter(stream), asyncStreamSerializer, resourceProvider) + { } [Obsolete("Cucumber.HtmlFormatter moving to async only operations. Please use the MessagesToHtmlWriter(StreamWriter, Func) constructor", false)] public MessagesToHtmlWriter(StreamWriter writer, Action streamSerializer) { - this._writer = writer; - this._streamSerializer = streamSerializer; + _writer = writer; + _streamSerializer = streamSerializer; // Create async wrapper for sync serializer - this._asyncStreamSerializer = (w, e) => + _asyncStreamSerializer = (w, e) => { streamSerializer(w, e); return Task.CompletedTask; }; - _template = GetResource("index.mustache.html"); + _resourceProvider = new DefaultResourceProvider(); + _template = _resourceProvider.GetTemplateResource(); _jsonInHtmlWriter = new JsonInHtmlWriter(writer); _isAsyncInitialized = false; } - public MessagesToHtmlWriter(StreamWriter writer, Func asyncStreamSerializer) + + public MessagesToHtmlWriter(StreamWriter writer, Func asyncStreamSerializer, IResourceProvider? resourceProvider = null) { - this._writer = writer; - this._asyncStreamSerializer = asyncStreamSerializer; + _writer = writer; + _asyncStreamSerializer = asyncStreamSerializer; // Create sync wrapper for async serializer (will block) - this._streamSerializer = (w, e) => asyncStreamSerializer(w, e).GetAwaiter().GetResult(); - _template = GetResource("index.mustache.html"); + _streamSerializer = (w, e) => asyncStreamSerializer(w, e).GetAwaiter().GetResult(); + _resourceProvider = resourceProvider ?? new DefaultResourceProvider(); + _template = _resourceProvider.GetTemplateResource(); _jsonInHtmlWriter = new JsonInHtmlWriter(writer); _isAsyncInitialized = true; } @@ -50,28 +57,28 @@ public MessagesToHtmlWriter(StreamWriter writer, Func