Files
kjol/go/webbundler/hmr_error_test.go

79 lines
2.5 KiB
Go

//go:build dev
package webbundler
import (
"errors"
"net/http/httptest"
"os"
"path/filepath"
"strings"
"testing"
esbuild "github.com/evanw/esbuild/pkg/api"
)
// errorModule must emit a valid ES module that imports the client's
// showErrorOverlay and calls it with the error text + file, so a failed
// transform pops the compile-error overlay instead of just logging.
func TestErrorModuleShape(t *testing.T) {
src := errorModule("ui/Broken.tsx", errors.New("Unexpected \"}\" at line 3"))
for _, want := range []string{
`from "/@hmr/client"`,
"showErrorOverlay",
"__hmrShowError(",
"ui/Broken.tsx",
`Unexpected`,
} {
if !strings.Contains(src, want) {
t.Errorf("errorModule() missing %q:\n%s", want, src)
}
}
// It must parse as an ES module (the payload is embedded JSON-as-JS).
res := esbuild.Transform(src, esbuild.TransformOptions{
Loader: esbuild.LoaderJS, Format: esbuild.FormatESModule, LogLevel: esbuild.LogLevelSilent,
})
if len(res.Errors) > 0 {
msgs := esbuild.FormatMessages(res.Errors, esbuild.FormatMessagesOptions{})
t.Fatalf("errorModule() is not valid JS:\n%s\n--- source ---\n%s", strings.Join(msgs, "\n"), src)
}
}
// A source file that fails to compile must be served as the overlay stub (HTTP
// 200, not a 500 that would tear the module graph), so the browser shows the
// error and the next save can recover.
func TestServeModuleCompileErrorServesOverlay(t *testing.T) {
root, err := filepath.Abs("../..")
if err != nil {
t.Fatal(err)
}
t.Chdir(root)
frontendAbs, _ := filepath.Abs(frontendDir)
tmpSrc := evalSymlinks(t.TempDir())
// Deliberately broken JSX: an unclosed tag the compiler/esbuild must reject.
os.WriteFile(filepath.Join(tmpSrc, "Broken.tsx"),
[]byte("export default function Broken() {\n return <div><span></div>;\n}\n"), 0o644)
eps, _ := loadVendorManifest(filepath.Join(frontendAbs, "vendor"))
d := &devServer{hub: newHub(), frontend: frontendAbs, srcRoot: tmpSrc,
vendor: filepath.Join(frontendAbs, "vendor"), graph: newModuleGraph(),
vendorCache: map[string][]byte{}, cssTrigger: make(chan struct{}, 1), vendorEntrypoints: eps}
req := httptest.NewRequest("GET", srcURLPrefix+"Broken.tsx", nil)
w := httptest.NewRecorder()
d.serveModule(w, req)
if w.Code != 200 {
t.Fatalf("broken module served status %d, want 200 (overlay stub)", w.Code)
}
body := w.Body.String()
for _, want := range []string{"showErrorOverlay", `from "/@hmr/client"`, "Broken.tsx"} {
if !strings.Contains(body, want) {
t.Errorf("overlay stub missing %q:\n%s", want, body)
}
}
}