146 lines
4.4 KiB
Go
146 lines
4.4 KiB
Go
package bundler
|
|
|
|
import (
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// entryHome renders the real home-page component the way ssrEntrySolid does:
|
|
// plain JS (createComponent, no JSX in the entry) importing the .tsx page, which
|
|
// the Go Solid compiler compiles. PublicLayout is omitted to target the body.
|
|
const entryHome = `
|
|
import { render, createComponent } from "solid-js/web";
|
|
import { Home } from "./frontend/src/pages/public/Home.tsx";
|
|
globalThis.__render = function () {
|
|
const root = document.createElement("div");
|
|
const dispose = render(function () { return createComponent(Home, {}); }, root);
|
|
const out = globalThis.__serialize(root);
|
|
dispose();
|
|
return out;
|
|
};
|
|
`
|
|
|
|
// Proves the ISR data-injection path the server uses: a pre-bundled render entry
|
|
// run in goja with server data injected (RenderBundleWithData) makes Home render
|
|
// the injected rates (via serverData()) instead of the loading skeleton.
|
|
func TestRenderHomeWithServerData(t *testing.T) {
|
|
root, err := filepath.Abs("../..")
|
|
if err != nil {
|
|
t.Fatalf("abs project root: %v", err)
|
|
}
|
|
t.Chdir(root)
|
|
|
|
data := `{"rates":[{"term":"90 Day","low":"1.111%","high":"2.222%","avg":"1.500%"}]}`
|
|
js, err := BundleEntry(entryHome, ".")
|
|
if err != nil {
|
|
t.Fatalf("bundle: %v", err)
|
|
}
|
|
out, err := RenderBundleWithData(js, data)
|
|
if err != nil {
|
|
t.Fatalf("render with data: %v", err)
|
|
}
|
|
for _, want := range []string{"1.111%", "2.222%", "1.500%"} {
|
|
if !strings.Contains(out, want) {
|
|
t.Errorf("output missing injected rate %q", want)
|
|
}
|
|
}
|
|
// With data present the table shows it, not the loading skeleton.
|
|
if strings.Contains(out, "animate-pulse") {
|
|
t.Errorf("skeleton rendered despite injected data")
|
|
}
|
|
}
|
|
|
|
// Reproduces the server's setup (cwd at repo root, relative "." project root).
|
|
// Guards the esbuild alias-resolution bug where a non-absolute root yields
|
|
// bare-specifier alias targets that fail to resolve.
|
|
func TestRenderWithRelativeRoot(t *testing.T) {
|
|
root, err := filepath.Abs("../..")
|
|
if err != nil {
|
|
t.Fatalf("abs project root: %v", err)
|
|
}
|
|
t.Chdir(root)
|
|
|
|
r := NewRenderer(".", entryHome, true)
|
|
out, err := r.HTML()
|
|
if err != nil {
|
|
t.Fatalf("render with relative root: %v", err)
|
|
}
|
|
if !strings.Contains(out, `class="page-home"`) {
|
|
t.Errorf("output missing page-home")
|
|
}
|
|
}
|
|
|
|
// Confirms the cache: the first HTML() pays bundle+render, the second (no source
|
|
// change) returns the cached string near-instantly.
|
|
func TestRendererCaching(t *testing.T) {
|
|
root, err := filepath.Abs("../..")
|
|
if err != nil {
|
|
t.Fatalf("abs project root: %v", err)
|
|
}
|
|
r := NewRenderer(root, entryHome, false) // prod: warm HTML() returns the cached string directly
|
|
|
|
t0 := time.Now()
|
|
first, err := r.HTML()
|
|
if err != nil {
|
|
t.Fatalf("cold render: %v", err)
|
|
}
|
|
cold := time.Since(t0)
|
|
|
|
t1 := time.Now()
|
|
second, err := r.HTML()
|
|
if err != nil {
|
|
t.Fatalf("warm render: %v", err)
|
|
}
|
|
warm := time.Since(t1)
|
|
t.Logf("cold=%v warm=%v", cold, warm)
|
|
|
|
if first != second {
|
|
t.Errorf("cached output differs from first render")
|
|
}
|
|
if warm > cold/4 {
|
|
t.Errorf("cache hit too slow: cold=%v warm=%v", cold, warm)
|
|
}
|
|
}
|
|
|
|
// No data → the home page renders its loading skeleton, exercising compiled Solid
|
|
// against inline SVGs (viewBox case), string style attributes, entities, and the
|
|
// table. SVG attribute case and the style string must survive serialization.
|
|
func TestRenderHomeSkeleton(t *testing.T) {
|
|
root, err := filepath.Abs("../..")
|
|
if err != nil {
|
|
t.Fatalf("abs project root: %v", err)
|
|
}
|
|
bundle, err := BundleEntry(entryHome, root)
|
|
if err != nil {
|
|
t.Fatalf("bundle: %v", err)
|
|
}
|
|
eng, err := New()
|
|
if err != nil {
|
|
t.Fatalf("engine: %v", err)
|
|
}
|
|
if err := eng.LoadBundle(bundle); err != nil {
|
|
t.Fatalf("load bundle: %v", err)
|
|
}
|
|
out, err := eng.Render()
|
|
if err != nil {
|
|
t.Fatalf("render: %v", err)
|
|
}
|
|
t.Logf("HOME SKELETON (%d bytes):\n%s", len(out), out)
|
|
|
|
for _, want := range []string{
|
|
`class="page-home"`,
|
|
`The Ultimate Funding and Investing Solution`,
|
|
`viewBox="0 0 24 24"`, // SVG attribute case preserved
|
|
`background-image: url(/images/public/hero-bg.jpg)`, // static string style baked into the template
|
|
`animate-pulse`, // skeleton bars (SSR forces showSkeleton)
|
|
`90 Day`, // term labels shown in the skeleton
|
|
`Schedule a free demo`,
|
|
} {
|
|
if !strings.Contains(out, want) {
|
|
t.Errorf("output missing %q", want)
|
|
}
|
|
}
|
|
}
|