diff --git a/e2e-tests/hydration-integration.spec.ts b/e2e-tests/hydration-integration.spec.ts new file mode 100644 index 0000000..41bfd2b --- /dev/null +++ b/e2e-tests/hydration-integration.spec.ts @@ -0,0 +1,413 @@ +/** + * Hydration Integration Tests + * + * Tests the patched @malloydata/render hydrate() method. + * These tests verify that pre-rendered HTML can be hydrated with interactivity. + */ +import { test, expect } from "@playwright/test"; +import * as fs from "fs"; +import * as path from "path"; + +const OUTPUT_DIR = path.join(process.cwd(), "prerender-output", "test-results"); + +test.beforeAll(() => { + if (!fs.existsSync(OUTPUT_DIR)) { + fs.mkdirSync(OUTPUT_DIR, { recursive: true }); + } +}); + +test.describe("Hydration Patch Verification", () => { + test("Verify hydrate() method exists on MalloyViz", async ({ page }) => { + await page.goto("./"); + + // Check if the hydrate method is available + const hasHydrate = await page.evaluate(async () => { + // The app uses MalloyRenderer from @malloydata/render + // We check if hydrate is defined by looking at the prototype + const script = document.createElement("script"); + script.type = "module"; + script.textContent = ` + import { MalloyRenderer } from '@malloydata/render'; + const renderer = new MalloyRenderer(); + const viz = renderer.createViz({}); + window.__hasHydrate = typeof viz.hydrate === 'function'; + `; + document.head.appendChild(script); + + // Wait for module to load + await new Promise((resolve) => setTimeout(resolve, 500)); + return (window as unknown as { __hasHydrate: boolean }).__hasHydrate; + }); + + console.log("hydrate() method exists:", hasHydrate); + // This test documents whether the patch was applied + // If false, the patch needs to be applied via npm install + }); + + test("Pre-render and capture HTML with marker", async ({ page }) => { + await page.goto("./#/model/invoices/query/by_status"); + await expect(page.getByRole("tab", { name: "Results" })).toBeVisible({ + timeout: 30000, + }); + + // Get the rendered HTML + const renderedHTML = await page.evaluate(() => { + const container = document.querySelector(".result-content > div"); + if (!container) return null; + + // Clone and add the prerender marker + const clone = container.cloneNode(true) as HTMLElement; + clone.setAttribute("data-malloy-prerendered", "true"); + + return { + original: container.innerHTML, + withMarker: clone.outerHTML, + hasTable: container.querySelector("table") !== null, + rowCount: container.querySelectorAll("tr").length, + }; + }); + + expect(renderedHTML).toBeTruthy(); + console.log("Pre-rendered content:"); + console.log(" - Has table:", renderedHTML?.hasTable); + console.log(" - Row count:", renderedHTML?.rowCount); + + // Save the pre-rendered HTML + if (renderedHTML) { + const htmlContent = ` + +
+ +