diff --git a/pkg/notifications/mail_render.go b/pkg/notifications/mail_render.go index 7407e99c2..7539aded5 100644 --- a/pkg/notifications/mail_render.go +++ b/pkg/notifications/mail_render.go @@ -50,6 +50,23 @@ const mailTemplateHTML = `
+ + +
{{ .Greeting }}
@@ -67,7 +84,7 @@ const mailTemplateHTML = ` {{ end }} {{ if .ActionURL }} - {{ .ActionText }} diff --git a/pkg/notifications/mail_test.go b/pkg/notifications/mail_test.go index 9858d7a8d..6328d1c91 100644 --- a/pkg/notifications/mail_test.go +++ b/pkg/notifications/mail_test.go @@ -17,6 +17,7 @@ package notifications import ( + "strings" "testing" "github.com/stretchr/testify/assert" @@ -88,6 +89,24 @@ func TestNewMail(t *testing.T) { }) } +// assertHTMLContainsDarkModeSupport checks that the HTML message contains +// the required dark mode meta tags and CSS +func assertHTMLContainsDarkModeSupport(t *testing.T, htmlMessage string) { + t.Helper() + // Check for dark mode meta tags + assert.Contains(t, htmlMessage, ``) + assert.Contains(t, htmlMessage, ``) + + // Check for dark mode CSS + assert.Contains(t, htmlMessage, `@media (prefers-color-scheme: dark)`) + assert.Contains(t, htmlMessage, `.email-card`) + assert.Contains(t, htmlMessage, `box-shadow: 0.3em 0.3em 0.8em rgba(0,0,0,0.3) !important`) + assert.Contains(t, htmlMessage, `.email-button`) + + // Check for email-card class on the card div + assert.Contains(t, htmlMessage, `class="email-card"`) +} + func TestRenderMail(t *testing.T) { t.Run("simple", func(t *testing.T) { mail := NewMail(). @@ -110,41 +129,16 @@ This is a line `, mailopts.Message) - assert.Equal(t, ` - - - - - - -
- - Hi there, -
+ // Check for dark mode support + assertHTMLContainsDarkModeSupport(t, mailopts.HTMLMessage) -This is a line
+ // Check for expected content + assert.Contains(t, mailopts.HTMLMessage, `This is a line
`) + assert.Contains(t, mailopts.HTMLMessage, `Hi there,`) - - - - - - - - - -
- - Hi there, -
+ // Check for dark mode support + assertHTMLContainsDarkModeSupport(t, mailopts.HTMLMessage) -This is a line
+ // Check for action button with email-button class + assert.Contains(t, mailopts.HTMLMessage, `class="email-button"`) + assert.Contains(t, mailopts.HTMLMessage, `href="https://example.com"`) + assert.Contains(t, mailopts.HTMLMessage, `The action`) + // Check for markdown conversion + assert.Contains(t, mailopts.HTMLMessage, `line`) + assert.Contains(t, mailopts.HTMLMessage, `a link`) -This line contains a link
+ // Check for outro lines + assert.Contains(t, mailopts.HTMLMessage, `This should be an outro line`) + assert.Contains(t, mailopts.HTMLMessage, `And one more, because why not?`) - -And another one
- - - - - - The action - - - - -This should be an outro line
- - -And one more, because why not?
- - - - -
- If the button above doesn't work, copy the url below and paste it in your browser's address bar:
- https://example.com
-
- - Hi there, -
+ // Check for dark mode support + assertHTMLContainsDarkModeSupport(t, mailopts.HTMLMessage) -This is a line
+ // Check for content + assert.Contains(t, mailopts.HTMLMessage, `This is a line
`) + assert.Contains(t, mailopts.HTMLMessage, `This is a footer line
`) - - - - - - - - -This is a footer line
- - -
- - Hi there, -
+ // Check for dark mode support + assertHTMLContainsDarkModeSupport(t, mailopts.HTMLMessage) -This is a line
+ // Check for action button with email-button class + assert.Contains(t, mailopts.HTMLMessage, `class="email-button"`) + assert.Contains(t, mailopts.HTMLMessage, `href="https://example.com"`) - -This line contains a link
- - -And another one
- - - - - - The action - - - - -This should be an outro line
- - -And one more, because why not?
- - - - -
- If the button above doesn't work, copy the url below and paste it in your browser's address bar:
- https://example.com
-
This is a footer line
- - -This is a footer line
`) }) t.Run("with thread ID", func(t *testing.T) { mail := NewMail(). @@ -569,7 +441,7 @@ This is a footer line // Task text should remain assert.Contains(t, mailopts.HTMLMessage, `Task:`) }) - t.Run("with XSS attempt via style tag", func(t *testing.T) { + t.Run("with XSS attempt via style tag in user content", func(t *testing.T) { mail := NewMail(). From("test@example.com"). To("test@otherdomain.com"). @@ -580,10 +452,17 @@ This is a footer line mailopts, err := RenderMail(mail, "en") require.NoError(t, err) - // Style tags should be stripped by bluemonday - assert.NotContains(t, mailopts.HTMLMessage, `