//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