diff --git a/test/manual/sse-multichannel.html b/test/manual/sse-multichannel.html
deleted file mode 100644
index 29b9ef88..00000000
--- a/test/manual/sse-multichannel.html
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
Multiple Listeners. message only
-
Waiting for Posts in Event1 channel...
-
Waiting for Posts in Event2 channel...
-
Waiting for Posts in Event3 channel...
-
Waiting for Posts in Event4 channel...
-
-
-
\ No newline at end of file
diff --git a/test/manual/sse-settle.html b/test/manual/sse-settle.html
deleted file mode 100644
index 87877cdc..00000000
--- a/test/manual/sse-settle.html
+++ /dev/null
@@ -1,50 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
Testing Triggers
-
Waiting for Posts in Event1 channel...
-
Waiting for Posts in Event2 channel...
-
Waiting for Posts in Event3 channel...
-
Waiting for Posts in Event4 channel...
-
-
-
-
-
\ No newline at end of file
diff --git a/test/manual/sse.html b/test/manual/sse.html
deleted file mode 100644
index c34e872a..00000000
--- a/test/manual/sse.html
+++ /dev/null
@@ -1,43 +0,0 @@
-
-
-
-
-
-
-
-
-
-
+
User: {{.name}} / {{.username}}
+
{{.email}}
+
{{.address.street}} {{.address.suite}}
{{.address.city}}, {{.address.zipcode}}
+
event: [[eventType]]
+
`)
+}
+
+// handleStream creates an echo.HandlerFunc that streams events from an eventSource to client browsers
+func handleStream(eventSource chan string) echo.HandlerFunc {
+
+ return func(ctx echo.Context) error {
+
+ w := ctx.Response().Writer
+
+ // Make sure that the writer supports flushing.
+ f, ok := w.(http.Flusher)
+
+ if !ok {
+ return derp.New(500, "handler.ServerSentEvent", "Streaming Not Supported")
+ }
+
+ c := ctx.Request().Context()
+
+ // Set the headers related to event streaming.
+ w.Header().Set("Content-Type", "text/event-stream")
+ w.Header().Set("Cache-Control", "no-cache")
+ w.Header().Set("Connection", "keep-alive")
+ w.Header().Set("Transfer-Encoding", "chunked")
+ w.Header().Set("Access-Control-Allow-Origin", "*")
+
+ types := []string{}
+
+ if param := ctx.QueryParam("types"); param != "" {
+ types = strings.Split(param, ",")
+ }
+
+ // Don't close the connection, instead loop endlessly.
+ for {
+
+ select {
+ case <-c.Done():
+ log.Println("HTTP connection just closed.")
+ return nil
+
+ case message := <-eventSource:
+
+ var eventType string
+
+ if len(types) > 0 {
+ eventType = types[rand.Int()%len(types)]
+ fmt.Fprintf(w, "event: %s\n", eventType)
+ }
+
+ message = strings.Replace(message, "\n", " ", -1)
+ message = strings.Replace(message, "[[eventType]]", eventType, 1)
+
+ fmt.Fprintf(w, "data: %s\n\n", message)
+
+ // Flush the response. This is only possible if the response supports streaming.
+ f.Flush()
+ }
+ }
+ }
+}
+
+// makeStream loops through an array of interfaces
+func makeStream(data []interface{}, format formatFunc) chan string {
+
+ result := make(chan string)
+
+ go func() {
+
+ for {
+ for _, record := range data {
+ result <- format(record)
+ time.Sleep((time.Duration(rand.Int() % 500)) * time.Millisecond)
+
+ }
+ }
+ }()
+
+ return result
+}
+
+func jsonFormatFunc(data interface{}) string {
+ result, _ := json.Marshal(data)
+ return string(result)
+}
+
+func templateFormatFunc(name string, text string) formatFunc {
+
+ f, _ := template.New(name).Parse(htmlconv.CollapseWhitespace(text))
+
+ return func(data interface{}) string {
+
+ var buffer bytes.Buffer
+
+ f.Execute(&buffer, data)
+
+ return buffer.String()
+ }
+}
diff --git a/test/servers/sse/static/black_transparent.svg b/test/servers/sse/static/black_transparent.svg
new file mode 100644
index 00000000..99db1a26
--- /dev/null
+++ b/test/servers/sse/static/black_transparent.svg
@@ -0,0 +1,9 @@
+
+
+
Description
+
+ This page connects to a single different Server Sent Event (SSE) stream, listening on events named "Event1", "Event2", "Event3", and "Event4".
+ Each separate kind of event should swap into a different container.
+
+
Example HTML
+
+<div hx-ext="sse" sse-url="http://localhost/posts.html?types=Event1%2cEvent2%2cEvent3%2cEvent4">
+ <div sse-swap="Event1">Waiting for Posts in Event1 channel...</div>
+</div>
+
+
Test Cases
+
Waiting for Posts in Event1 channel...
+
Waiting for Posts in Event2 channel...
+
Waiting for Posts in Event3 channel...
+
Waiting for Posts in Event4 channel...
+
+
+
diff --git a/test/servers/sse/static/sse-settle.html b/test/servers/sse/static/sse-settle.html
new file mode 100644
index 00000000..9987e576
--- /dev/null
+++ b/test/servers/sse/static/sse-settle.html
@@ -0,0 +1,33 @@
+
+
+
+
+
Description
+
+ This page connects to a single different Server Sent Event (SSE) stream.
+ Multiple containers all listen for the same default "message" event name, but using different values for hx-swap.
+
+
Example HTML
+
+<div hx-ext="sse" sse-url="http://localhost/comments.html">
+ <div sse-swap="message" hx-swap="settle:100ms">Waiting for Comments...</div>
+</div>
+
+
Test Cases
+
+
Waiting for Comments...
+
Waiting for Comments...
+
Waiting for Comments...
+
Waiting for Comments...
+
Waiting for Comments...
+
+
+
+
\ No newline at end of file
diff --git a/test/servers/sse/static/sse-target.html b/test/servers/sse/static/sse-target.html
new file mode 100644
index 00000000..5e549765
--- /dev/null
+++ b/test/servers/sse/static/sse-target.html
@@ -0,0 +1,34 @@
+
+
+
+
+
Description
+
+ This page connects to several different different Server Sent Event (SSE) stream.
+ Contents from each stream are sent to a single DOM element.
+
+
Example HTML
+
+<div sse-connect="/users/sse.html" sse-target="#otherNode"></div>
+<div id="otherNode"></div>
+
+
Test Cases
+
+
Multiple Listeners using HX-Target to write to a single target node.
+
+
+
+
+
+
+
Waiting for records from any of: Posts/Comments/Albums/ToDos/Users
+
+
+