package gateway import ( "strings" "testing" ) // The plugin UI injection is JavaScript inside the embedded index.html, and it // is the ONLY thing that turns a plugin's `ui` block into a visible page or // element. These tests pin the wiring on the JS side; the server side (what the // payload contains) is covered by TestUIInjectServesPluginUI and the lua // package's TestBillingPluginDeclaresUI. // // What makes this worth pinning: a missing hook here fails SILENTLY. The page // simply never appears, there is no error anywhere, and it looks like "the // plugin didn't declare a page" rather than "the UI forgot to inject it". // uiSource returns the embedded WebUI document. func uiSourceX(t *testing.T) string { t.Helper() return uiSource(t) } // TestUIFetchesPluginInjection: the boot sequence must ask the kernel what to // inject. Without this fetch the whole feature is inert. func TestUIFetchesPluginInjection(t *testing.T) { src := uiSourceX(t) if !strings.Contains(src, "/api/ui-inject") { t.Error("the WebUI never calls /api/ui-inject; plugin pages and elements can never appear") } } // TestUIInjectsBeforeFirstRender: injection must be awaited before the first // refresh, otherwise the sidebar is built without the plugin entry and the // first paint races the fetch. This is an ordering contract, so it is asserted // on the source order rather than trusted. func TestUIInjectsBeforeFirstRender(t *testing.T) { src := uiSourceX(t) iInject := strings.Index(src, "injectPluginUI()") iRefresh := strings.LastIndex(src, `refresh("status")`) if iInject < 0 { t.Fatal("injectPluginUI() is never called") } if iRefresh < 0 { t.Fatal("the boot sequence no longer calls refresh(\"status\")") } if iInject > iRefresh { t.Error("injectPluginUI() is called after the first refresh; the sidebar " + "and #main would be built before the plugin page exists") } // And it must be awaited, not fire-and-forget. window := src[iInject:] if !strings.Contains(window[:200], ".finally") && !strings.Contains(window[:200], "await") { t.Error("injectPluginUI() is not awaited before refresh; a slow response " + "would race the first paint") } } // TestUIPluginScriptsRunAfterMarkup is the subtle one. Setting innerHTML with a //