From 58cb444bf247569d36d6137103e4cc2fe2f2de96 Mon Sep 17 00:00:00 2001 From: Tom Butcher Date: Sat, 12 Sep 2026 23:48:03 +0100 Subject: [PATCH] Refactor email template rendering to support preview mode and improve CSS handling This commit updates the email template rendering logic to conditionally apply a preview wrapper and associated CSS when the preview flag is set. It modifies the `renderEmailTemplate` and `renderTemplate` methods to ensure that the email content is correctly wrapped in a preview structure, while also ensuring that scaling is consistently applied. Additionally, tests are added to verify the correct behavior of the rendering process in both preview and non-preview scenarios, enhancing the overall functionality of the TemplateManager. --- .../__tests__/templatemanager.test.js | 71 ++++++++++++++++++- src/templates/templatemanager.js | 35 +++++---- 2 files changed, 92 insertions(+), 14 deletions(-) diff --git a/src/templates/__tests__/templatemanager.test.js b/src/templates/__tests__/templatemanager.test.js index 840b918..40a0db2 100644 --- a/src/templates/__tests__/templatemanager.test.js +++ b/src/templates/__tests__/templatemanager.test.js @@ -203,11 +203,44 @@ describe('TemplateManager', () => { ); expect(result.subject).toBe('rendered: Hello'); - expect(result.html).toContain('max-width:640px'); - expect(result.html).toContain('transformed: rendered: Body'); + expect(result.html).toContain('width: 640px'); + expect(result.html).toContain('class="preview"'); + expect(ejs.render).toHaveBeenCalledWith( + '
<%- content %>
', + expect.objectContaining({ + content: 'transformed: rendered: Body', + }), + expect.objectContaining({ async: true }) + ); expect(result).not.toHaveProperty('height'); expect(result).not.toHaveProperty('intellisense'); }); + + it('does not wrap sent email HTML in the preview template', async () => { + getObject.mockResolvedValue({ + _reference: 'EMAIL1', + active: true, + global: true, + subject: 'Hello', + content: 'Body', + }); + + const result = await templateManager.renderEmailTemplate( + 'email-template-id', + undefined, + undefined, + { name: 'Test' }, + {}, + false + ); + + expect(result.html).toContain('transformed: rendered: Body'); + expect(ejs.render).not.toHaveBeenCalledWith( + '
<%- content %>
', + expect.anything(), + expect.anything() + ); + }); }); describe('renderTemplate', () => { @@ -230,6 +263,40 @@ describe('TemplateManager', () => { expect(result.width).toBe(100); expect(result.height).toBe(100); expect(result).not.toHaveProperty('intellisense'); + expect(ejs.render).toHaveBeenCalledWith( + '<%- content %>', + expect.objectContaining({ + scale: '1', + scaledWidth: '100mm', + scaledPageWidth: '100mm', + }), + expect.anything() + ); + }); + + it('does not apply zoom in preview HTML even when a scale is requested', async () => { + getObject.mockResolvedValue({ + documentSize: { width: 100, height: 100, infiniteHeight: false }, + global: false, + objectType: 'printer', + }); + + await templateManager.renderTemplate( + 'temp-id', + 'some content', + { name: 'Test' }, + 2.5 + ); + + expect(ejs.render).toHaveBeenCalledWith( + '<%- content %>', + expect.objectContaining({ + scale: '1', + scaledWidth: '100mm', + scaledHeight: '100mm', + }), + expect.anything() + ); }); it('does not return intellisense when preview render throws', async () => { diff --git a/src/templates/templatemanager.js b/src/templates/templatemanager.js index 226624e..fa4c56c 100644 --- a/src/templates/templatemanager.js +++ b/src/templates/templatemanager.js @@ -786,18 +786,29 @@ export class TemplateManager { pixelId != null ? `` : ''; - const emailContent = - preview === true - ? `
${transformed}
` - : transformed; + let emailContent = transformed; + let previewCss = ''; + if (preview === true) { + emailContent = await ejs.render(previewTemplate, { content: transformed }, renderOptions); + previewCss = ` + .previewWrapper { + width: ${width}px; + height: auto; + } + .previewDocument { + width: ${width}px; + height: auto; + overflow: visible; + }`; + } const outerHtml = (css, content, pixel = undefined) => { return `${pixel != undefined ? pixel : ''}${content}`; }; return { subject: renderedSubject, - html: outerHtml(baseCSS, emailContent), - htmlWithPixel: outerHtml(baseCSS, emailContent, renderedPixel), + html: outerHtml(`${baseCSS}${previewCss}`, emailContent), + htmlWithPixel: outerHtml(`${baseCSS}${previewCss}`, emailContent, renderedPixel), }; } catch (error) { logger.warn('Error whilst rendering email template:', error.message); @@ -841,7 +852,7 @@ export class TemplateManager { return object; } - async renderTemplate(id, content, data = {}, scale = 1, options = {}, preview = true) { + async renderTemplate(id, content, data = {}, _scale = 1, options = {}, preview = true) { try { const { padding: paddingRequested = false, @@ -994,15 +1005,15 @@ export class TemplateManager { content: innerHtml, width: `${documentSize.width}mm`, height: infiniteHeight ? 'fit-content' : `${documentSize.height}mm`, - scaledWidth: `${documentSize.width * scale}mm`, - scaledHeight: infiniteHeight ? 'auto' : `${documentSize.height * scale}mm`, - scaledPageWidth: `${pageWidth * scale}mm`, - scaledPageHeight: infiniteHeight ? 'auto' : `${pageHeight * scale}mm`, + scaledWidth: `${documentSize.width}mm`, + scaledHeight: infiniteHeight ? 'auto' : `${documentSize.height}mm`, + scaledPageWidth: `${pageWidth}mm`, + scaledPageHeight: infiniteHeight ? 'auto' : `${pageHeight}mm`, paddingTop: `${padding.paddingTop}mm`, paddingRight: `${padding.paddingRight}mm`, paddingBottom: `${padding.paddingBottom}mm`, paddingLeft: `${padding.paddingLeft}mm`, - scale: `${scale}`, + scale: '1', baseCSS: baseCSS, infiniteHeight: infiniteHeight, pageWidth: `${pageWidth}mm`,