1
0
mirror of https://github.com/axllent/mailpit.git synced 2025-03-19 21:28:07 +02:00

Testing: Add endpoints for integration tests

See #166
This commit is contained in:
Ralph Slooten 2023-09-27 17:29:03 +13:00
parent 1020f76bf8
commit ae15cac727
4 changed files with 249 additions and 6 deletions

View File

@ -81,6 +81,13 @@ type textResponse struct {
Body string
}
// HTML response
// swagger:response HTMLResponse
type htmlResponse struct {
// in: body
Body string
}
// Error response
// swagger:response ErrorResponse
type errorResponse struct {

View File

@ -0,0 +1,163 @@
package handlers
import (
"fmt"
"net/http"
"regexp"
"strings"
"github.com/axllent/mailpit/config"
"github.com/axllent/mailpit/internal/storage"
"github.com/gorilla/mux"
)
// GetMessageHTML (method: GET) returns a rendered version of a message's HTML part
func GetMessageHTML(w http.ResponseWriter, r *http.Request) {
// swagger:route GET /view/{ID}.html testing GetMessageHTML
//
// # Render message HTML part
//
// Renders just the message's HTML part which can be used for UI integration testing.
// Attached inline images are modified to link to the API provided they exist.
// Note that is the message does not contain a HTML part then an 404 error is returned.
//
// The ID can be set to `latest` to return the latest message.
//
// Produces:
// - text/html
//
// Schemes: http, https
//
// Parameters:
// + name: ID
// in: path
// description: Database ID or latest
// required: true
// type: string
//
// Responses:
// 200: HTMLResponse
// default: ErrorResponse
vars := mux.Vars(r)
id := vars["id"]
if id == "latest" {
messages, err := storage.List(0, 1)
if err != nil {
httpError(w, err.Error())
return
}
if len(messages) == 0 {
w.WriteHeader(404)
fmt.Fprint(w, "Message not found")
return
}
id = messages[0].ID
}
msg, err := storage.GetMessage(id)
if err != nil {
w.WriteHeader(404)
fmt.Fprint(w, "Message not found")
return
}
if msg.HTML == "" {
w.WriteHeader(404)
fmt.Fprint(w, "This message does not contain a HTML part")
return
}
html := linkInlinedImages(msg)
w.Header().Add("Content-Type", "text/html; charset=utf-8")
_, _ = w.Write([]byte(html))
}
// GetMessageText (method: GET) returns a message's text part
func GetMessageText(w http.ResponseWriter, r *http.Request) {
// swagger:route GET /view/{ID}.txt testing GetMessageText
//
// # Render message text part
//
// Renders just the message's text part which can be used for UI integration testing.
//
// The ID can be set to `latest` to return the latest message.
//
// Produces:
// - text/plain
//
// Schemes: http, https
//
// Parameters:
// + name: ID
// in: path
// description: Database ID or latest
// required: true
// type: string
//
// Responses:
// 200: TextResponse
// default: ErrorResponse
vars := mux.Vars(r)
id := vars["id"]
if id == "latest" {
messages, err := storage.List(0, 1)
if err != nil {
httpError(w, err.Error())
return
}
if len(messages) == 0 {
w.WriteHeader(404)
fmt.Fprint(w, "Message not found")
return
}
id = messages[0].ID
}
msg, err := storage.GetMessage(id)
if err != nil {
w.WriteHeader(404)
fmt.Fprint(w, "Message not found")
return
}
w.Header().Add("Content-Type", "text/plain; charset=utf-8")
_, _ = w.Write([]byte(msg.Text))
}
// This will remap all attachment images with relative paths
func linkInlinedImages(msg *storage.Message) string {
html := msg.HTML
for _, a := range msg.Inline {
if a.ContentID != "" {
re := regexp.MustCompile(`(?i)(=["\']?)(cid:` + regexp.QuoteMeta(a.ContentID) + `)(["|\'|\\s|\\/|>|;])`)
u := config.Webroot + "api/v1/message/" + msg.ID + "/part/" + a.PartID
matches := re.FindAllStringSubmatch(html, -1)
for _, m := range matches {
html = strings.ReplaceAll(html, m[0], m[1]+u+m[3])
}
}
}
for _, a := range msg.Attachments {
if a.ContentID != "" {
re := regexp.MustCompile(`(?i)(=["\']?)(cid:` + regexp.QuoteMeta(a.ContentID) + `)(["|\'|\\s|\\/|>|;])`)
u := config.Webroot + "api/v1/message/" + msg.ID + "/part/" + a.PartID
matches := re.FindAllStringSubmatch(html, -1)
for _, m := range matches {
html = strings.ReplaceAll(html, m[0], m[1]+u+m[3])
}
}
}
return html
}

View File

@ -67,8 +67,14 @@ func Listen() {
r.HandleFunc(redirect, middleWareFunc(addSlashToWebroot)).Methods("GET")
}
// handle everything else with the virtual index.html
r.PathPrefix(config.Webroot).Handler(middleWareFunc(index)).Methods("GET")
// frontend testing
r.HandleFunc(config.Webroot+"view/{id}.html", handlers.GetMessageHTML).Methods("GET")
r.HandleFunc(config.Webroot+"view/{id}.txt", handlers.GetMessageText).Methods("GET")
// web UI via virtual index.html
r.PathPrefix(config.Webroot + "view/").Handler(middleWareFunc(index)).Methods("GET")
r.Path(config.Webroot + "search").Handler(middleWareFunc(index)).Methods("GET")
r.Path(config.Webroot).Handler(middleWareFunc(index)).Methods("GET")
// put it all together
http.Handle("/", r)
@ -293,10 +299,6 @@ func index(w http.ResponseWriter, _ *http.Request) {
buff.Bytes()
// f, err := embeddedFS.ReadFile("public/index.html")
// if err != nil {
// panic(err)
// }
w.Header().Add("Content-Type", "text/html")
_, _ = w.Write(buff.Bytes())
}

View File

@ -654,6 +654,74 @@
}
}
}
},
"/view/{ID}.html": {
"get": {
"description": "Renders just the message's HTML part which can be used for UI integration testing.\nAttached inline images are modified to link to the API provided they exist.\nNote that is the message does not contain a HTML part then an 404 error is returned.\n\nThe ID can be set to `latest` to return the latest message.",
"produces": [
"text/html"
],
"schemes": [
"http",
"https"
],
"tags": [
"testing"
],
"summary": "Render message HTML part",
"operationId": "GetMessageHTML",
"parameters": [
{
"type": "string",
"description": "Database ID or latest",
"name": "ID",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"$ref": "#/responses/HTMLResponse"
},
"default": {
"$ref": "#/responses/ErrorResponse"
}
}
}
},
"/view/{ID}.txt": {
"get": {
"description": "Renders just the message's text part which can be used for UI integration testing.\n\nThe ID can be set to `latest` to return the latest message.",
"produces": [
"text/plain"
],
"schemes": [
"http",
"https"
],
"tags": [
"testing"
],
"summary": "Render message text part",
"operationId": "GetMessageText",
"parameters": [
{
"type": "string",
"description": "Database ID or latest",
"name": "ID",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"$ref": "#/responses/TextResponse"
},
"default": {
"$ref": "#/responses/ErrorResponse"
}
}
}
}
},
"definitions": {
@ -1300,6 +1368,9 @@
"ErrorResponse": {
"description": "Error response"
},
"HTMLResponse": {
"description": "HTML response"
},
"InfoResponse": {
"description": "Application information",
"schema": {