Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,4 @@ trace-correlation/trace-correlation
testing/01_basic/basic
todos-components/todos-components
todos-components/.uploads/
.worktrees/
9 changes: 5 additions & 4 deletions avatar-upload/avatar-upload_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -315,12 +315,12 @@ func createTestImage(t *testing.T) (string, error) {
// This test reproduces the actual browser upload behavior
func TestUploadViaWebSocket(t *testing.T) {
// Create test server
store := &ProfileStore{
state := &ProfileState{
Name: "John Doe",
Email: "john@example.com",
}

handler := createTestHandler(t, store)
handler := createTestHandler(t, state)
server := httptest.NewServer(handler)
defer server.Close()

Expand Down Expand Up @@ -569,7 +569,7 @@ func getKeys(m map[string]interface{}) []string {
return keys
}

func createTestHandler(t *testing.T, store *ProfileStore) http.Handler {
func createTestHandler(t *testing.T, state *ProfileState) http.Handler {
// Same setup as main.go
lt, err := livetemplate.New("avatar-upload",
livetemplate.WithParseFiles("avatar-upload.tmpl"),
Expand All @@ -586,5 +586,6 @@ func createTestHandler(t *testing.T, store *ProfileStore) http.Handler {
t.Fatalf("Failed to create LiveTemplate: %v", err)
}

return lt.Handle(store)
controller := &ProfileController{}
return lt.Handle(controller, livetemplate.AsState(state))
}
3 changes: 2 additions & 1 deletion avatar-upload/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"path/filepath"

"github.com/livetemplate/livetemplate"
lvttest "github.com/livetemplate/lvt/testing"
)

//go:embed *.tmpl
Expand Down Expand Up @@ -153,7 +154,7 @@ func main() {
http.Handle("/uploads/", http.StripPrefix("/uploads/", http.FileServer(http.Dir("uploads"))))

// Serve client library
http.Handle("/client/", http.StripPrefix("/client/", http.FileServer(http.Dir("../../client/dist"))))
http.HandleFunc("/livetemplate-client.js", lvttest.ServeClientLibrary)

// Mount the LiveTemplate handler
http.Handle("/", handler)
Expand Down
51 changes: 27 additions & 24 deletions chat/chat_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import (
"context"
"fmt"
"net/http"
"os/exec"
"strings"
"testing"
"time"

"github.com/chromedp/chromedp"
e2etest "github.com/livetemplate/lvt/testing"
)

// waitFor polls a JavaScript condition until it returns true or timeout is reached
Expand Down Expand Up @@ -39,29 +39,30 @@ func TestChatE2E(t *testing.T) {
t.Skip("Skipping E2E test in short mode")
}

// Use fixed port for simplicity
serverPort := 8096
serverURL := fmt.Sprintf("http://localhost:%d", serverPort)

// Start chat server
t.Logf("Starting test server on port %d", serverPort)
serverCmd := exec.Command("go", "run", "main.go")
serverCmd.Env = append(serverCmd.Environ(), fmt.Sprintf("PORT=%d", serverPort))
// Get free ports for server and Chrome debugging
serverPort, err := e2etest.GetFreePort()
if err != nil {
t.Fatalf("Failed to get free port for server: %v", err)
}

// Don't capture stdout/stderr to avoid I/O blocking
if err := serverCmd.Start(); err != nil {
t.Fatalf("Failed to start server: %v", err)
debugPort, err := e2etest.GetFreePort()
if err != nil {
t.Fatalf("Failed to get free port for Chrome: %v", err)
}

// Start chat server using e2etest helper
serverCmd := e2etest.StartTestServer(t, "main.go", serverPort)
defer func() {
if serverCmd != nil && serverCmd.Process != nil {
serverCmd.Process.Kill()
// Don't call Wait() - it blocks on I/O
}
}()

serverURL := fmt.Sprintf("http://localhost:%d", serverPort)

// Wait for server to be ready
ready := false
for i := 0; i < 50; i++ { // 5 seconds
for i := 0; i < 100; i++ { // 10 seconds
resp, err := http.Get(serverURL)
if err == nil {
resp.Body.Close()
Expand All @@ -72,20 +73,19 @@ func TestChatE2E(t *testing.T) {
}

if !ready {
serverCmd.Process.Kill()
t.Fatal("Server failed to start within 5 seconds")
t.Fatal("Server failed to start within 10 seconds")
}

t.Logf("✅ Test server ready at %s", serverURL)

// Use local Chrome instead of Docker for simplicity
opts := append(chromedp.DefaultExecAllocatorOptions[:],
chromedp.Flag("headless", true),
chromedp.Flag("disable-gpu", true),
chromedp.Flag("no-sandbox", true),
)
// Start Docker Chrome container
chromeCmd := e2etest.StartDockerChrome(t, debugPort)
defer e2etest.StopDockerChrome(t, debugPort)
_ = chromeCmd // Command returned for reference; cleanup handled by StopDockerChrome

allocCtx, allocCancel := chromedp.NewExecAllocator(context.Background(), opts...)
// Connect to Docker Chrome via remote debugging
chromeURL := fmt.Sprintf("http://localhost:%d", debugPort)
allocCtx, allocCancel := chromedp.NewRemoteAllocator(context.Background(), chromeURL)
defer allocCancel()

browserCtx, cancelBrowser := chromedp.NewContext(allocCtx, chromedp.WithLogf(t.Logf))
Expand All @@ -95,11 +95,14 @@ func TestChatE2E(t *testing.T) {
browserCtx, cancelTimeout := context.WithTimeout(browserCtx, 120*time.Second)
defer cancelTimeout()

// URL for Docker Chrome to access the server
chromeTestURL := e2etest.GetChromeTestURL(serverPort)

t.Run("Initial_Load", func(t *testing.T) {
var initialHTML string

err := chromedp.Run(browserCtx,
chromedp.Navigate(serverURL),
chromedp.Navigate(chromeTestURL),
chromedp.WaitVisible(`[data-lvt-id]`, chromedp.ByQuery),
waitFor(`typeof window.liveTemplateClient !== 'undefined'`, 5*time.Second),
chromedp.WaitVisible(`input[name="username"]`, chromedp.ByQuery),
Expand Down
63 changes: 32 additions & 31 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,41 @@ go 1.25.3

require (
github.com/chromedp/chromedp v0.14.2
github.com/go-playground/validator/v10 v10.28.0
github.com/go-playground/validator/v10 v10.30.1
github.com/google/uuid v1.6.0
github.com/gorilla/websocket v1.5.3
github.com/livetemplate/components v0.0.0-20251224004709-1f8c1de230b4
github.com/livetemplate/livetemplate v0.7.7
github.com/livetemplate/lvt v0.0.0-20251130141940-9b94cde94e9d
modernc.org/sqlite v1.39.1
github.com/livetemplate/livetemplate v0.7.12
github.com/livetemplate/lvt v0.0.0-20260110064539-b9afb9e6df26
modernc.org/sqlite v1.43.0
)

require (
github.com/aws/aws-sdk-go-v2 v1.39.6 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3 // indirect
github.com/aws/aws-sdk-go-v2/config v1.31.17 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.18.21 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.13 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.13 // indirect
github.com/aws/aws-sdk-go-v2 v1.41.1 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 // indirect
github.com/aws/aws-sdk-go-v2/config v1.32.7 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.19.7 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.13 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.13 // indirect
github.com/aws/aws-sdk-go-v2/service/s3 v1.90.0 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.30.1 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.5 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.39.1 // indirect
github.com/aws/smithy-go v1.23.2 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17 // indirect
github.com/aws/aws-sdk-go-v2/service/s3 v1.95.1 // indirect
github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.30.9 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 // indirect
github.com/aws/smithy-go v1.24.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/chromedp/cdproto v0.0.0-20250724212937-08a3db8b4327 // indirect
github.com/chromedp/sysutil v1.1.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/gabriel-vasile/mimetype v1.4.11 // indirect
github.com/gabriel-vasile/mimetype v1.4.12 // indirect
github.com/go-json-experiment/json v0.0.0-20250725192818-e39067aee2d2 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
Expand All @@ -46,18 +47,18 @@ require (
github.com/gobwas/ws v1.4.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/redis/go-redis/v9 v9.16.0 // indirect
github.com/ncruces/go-strftime v1.0.0 // indirect
github.com/redis/go-redis/v9 v9.17.2 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/tdewolff/minify/v2 v2.24.6 // indirect
github.com/tdewolff/minify/v2 v2.24.8 // indirect
github.com/tdewolff/parse/v2 v2.8.5 // indirect
golang.org/x/crypto v0.43.0 // indirect
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
golang.org/x/net v0.46.0 // indirect
golang.org/x/sys v0.37.0 // indirect
golang.org/x/text v0.30.0 // indirect
golang.org/x/crypto v0.46.0 // indirect
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 // indirect
golang.org/x/net v0.48.0 // indirect
golang.org/x/sys v0.40.0 // indirect
golang.org/x/text v0.33.0 // indirect
golang.org/x/time v0.14.0 // indirect
modernc.org/libc v1.66.10 // indirect
modernc.org/libc v1.67.4 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect
)
Loading