Ctrl K
ComunidadGuías…

internal/ui/embed_test.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package ui

import (
	"crypto/sha256"
	"encoding/base64"
	"io"
	"log/slog"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
	"testing/fstest"
)

const indexHTML = `<!doctype html><html><head><script src="/config.js"></script></head><body></body></html>`

var testFS = fstest.MapFS{
	"index.html":              {Data: []byte(indexHTML)},
	"config.js":               {Data: []byte(`window.__SPARROW_CONFIG__ = window.__SPARROW_CONFIG__ || {};`)},
	"_app/immutable/entry.js": {Data: []byte(`console.log("app")`)},
}

func serve(t *testing.T, path string) (*http.Response, string) {
	t.Helper()
	h := newHandler(slog.New(slog.NewTextHandler(io.Discard, nil)), testFS)
	rec := httptest.NewRecorder()
	h.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, path, nil))
	res := rec.Result()
	body, _ := io.ReadAll(res.Body)
	return res, string(body)
}

// The server never writes a credential (or any config) into served pages:
// admin and portal pages alike are the built index.html, byte for byte.
func TestHandlerServesIndexUntouched(t *testing.T) {
	for _, path := range []string{"/", "/webhooks", "/events/instances/abc", "/portal", "/portal/webhooks"} {
		_, body := serve(t, path)
		if body != indexHTML {
			t.Fatalf("%s: body = %q, want untouched index.html", path, body)
		}
	}
}

func TestHandlerServesStaticConfigAndAssets(t *testing.T) {
	res, body := serve(t, "/config.js")
	if res.StatusCode != http.StatusOK || strings.Contains(body, "apiKey") {
		t.Fatalf("/config.js: status %d body %q", res.StatusCode, body)
	}
	if cc := res.Header.Get("Cache-Control"); strings.Contains(cc, "immutable") {
		t.Fatalf("/config.js must not be cached as immutable (operators edit it), got %q", cc)
	}

	res, _ = serve(t, "/_app/immutable/entry.js")
	if cc := res.Header.Get("Cache-Control"); !strings.Contains(cc, "immutable") {
		t.Fatalf("hashed asset Cache-Control = %q, want immutable", cc)
	}
}

func TestComputeInlineScriptHashes(t *testing.T) {
	t.Run("no inline scripts", func(t *testing.T) {
		html := []byte(`<!doctype html><html><head><script src="/app.js"></script></head><body></body></html>`)
		hashes := computeInlineScriptHashes(html)
		if len(hashes) != 0 {
			t.Errorf("expected no hashes for external-only scripts, got %v", hashes)
		}
	})

	t.Run("one inline script", func(t *testing.T) {
		body := `console.log("hello")`
		html := []byte(`<html><body><script>` + body + `</script></body></html>`)
		hashes := computeInlineScriptHashes(html)
		if len(hashes) != 1 {
			t.Fatalf("expected 1 hash, got %d: %v", len(hashes), hashes)
		}
		h := sha256.Sum256([]byte(body))
		want := "'sha256-" + base64.StdEncoding.EncodeToString(h[:]) + "'"
		if hashes[0] != want {
			t.Errorf("hash = %s, want %s", hashes[0], want)
		}
	})

	t.Run("mixed inline and external", func(t *testing.T) {
		html := []byte(`<html><head><script src="/config.js"></script></head><body><script>var x=1;</script></body></html>`)
		hashes := computeInlineScriptHashes(html)
		if len(hashes) != 1 {
			t.Fatalf("expected 1 hash (inline only), got %d: %v", len(hashes), hashes)
		}
	})

	t.Run("sveltekit bootstrap script", func(t *testing.T) {
		// Simulate a SvelteKit-style inline bootstrap script.
		html := []byte(`<!doctype html><html><head><script src="/config.js"></script></head><body>
<div style="display: contents">
	<script>
		{
			__sveltekit_test = { base: "" };
			import("/_app/entry/start.js").then(([kit, app]) => {
				kit.start(app, document.currentScript.parentElement);
			});
		}
	</script>
</div></body></html>`)
		hashes := computeInlineScriptHashes(html)
		if len(hashes) != 1 {
			t.Fatalf("expected 1 hash, got %d: %v", len(hashes), hashes)
		}
		if !strings.HasPrefix(hashes[0], "'sha256-") {
			t.Errorf("hash format wrong: %s", hashes[0])
		}
	})
}

func TestInlineScriptHashesFromFS(t *testing.T) {
	t.Run("no index.html", func(t *testing.T) {
		fs := fstest.MapFS{}
		hashes := inlineScriptHashesFromFS(fs)
		if hashes != nil {
			t.Errorf("expected nil for missing index.html, got %v", hashes)
		}
	})

	t.Run("index with no inline scripts", func(t *testing.T) {
		fs := fstest.MapFS{
			"index.html": {Data: []byte(indexHTML)}, // only has <script src=...>
		}
		hashes := inlineScriptHashesFromFS(fs)
		if len(hashes) != 0 {
			t.Errorf("expected no hashes, got %v", hashes)
		}
	})
}