| 1 | import assert from "node:assert/strict"; |
| 2 | import { readFileSync } from "node:fs"; |
| 3 | import React from "react"; |
| 4 | import { renderToStaticMarkup } from "react-dom/server"; |
| 5 | import { JSDOM } from "jsdom"; |
| 6 | import { AppBottomRegions } from "../app-shell/AppBottomRegions"; |
| 7 | import { register } from "node:module"; |
| 8 | import type { Translator } from "../lib/i18n"; |
| 9 | |
| 10 | const noop = () => {}; |
| 11 | register(new URL("../../scripts/svg-loader.mjs", import.meta.url)); |
| 12 | const { SidebarRegion } = await import("../app-shell/SidebarRegion"); |
| 13 | const t = ((key: string) => key) as Translator; |
| 14 | const topicbarActionsSource = readFileSync(new URL("../app-shell/TopicbarActionsStack.tsx", import.meta.url), "utf8"); |
| 15 | assert.doesNotMatch(topicbarActionsSource, /onOpenPalette|\bSearch\b/, "the topic bar no longer owns the command-palette entry"); |
| 16 | for (const automation of [false, true]) { |
| 17 | const markup = renderToStaticMarkup(<> |
| 18 | <SidebarRegion className="sidebar" collapsed={false} t={t} |
| 19 | onNewSession={noop} onOpenPalette={noop} paletteShortcut="Cmd+K" |
| 20 | onOpenTrash={noop} onOpenAutomation={noop} onOpenSettings={noop} |
| 21 | resize={{ min: 180, max: 400, value: 240, onPointerDown: noop, onKeyDown: noop, onReset: noop }} |
| 22 | projectTree={{ onOpenTopic: noop, onCreateTopic: noop, onTopicsChanged: noop }} /> |
| 23 | <AppBottomRegions terminal={{ surfaceVisible: !automation, open: !automation, |
| 24 | contentVisible: false, remoteSurface: false, t, |
| 25 | panel: { tabId: "tab", open: !automation, onClose: noop }, |
| 26 | resizer: { min: 100, max: 400, value: 240, onPointerDown: noop, onKeyDown: noop, onReset: noop }, |
| 27 | }} /> |
| 28 | </>); |
| 29 | const dom = new JSDOM(markup); |
| 30 | const doc = dom.window.document; |
| 31 | assert.equal(doc.querySelectorAll(".terminal-drawer").length, 1, "terminal host survives page projection"); |
| 32 | assert.equal(doc.querySelector(".terminal-drawer")?.hasAttribute("inert"), automation); |
| 33 | assert.equal(doc.querySelectorAll(".terminal-drawer-resizer").length, automation ? 0 : 1); |
| 34 | assert.equal(doc.querySelectorAll(".sidebar-collapse-toggle").length, 0, "the workbench sidebar has no collapse toggle"); |
| 35 | const automationButtons = [...doc.querySelectorAll("button")].filter(button => button.querySelector(".lucide-alarm-clock")); |
| 36 | assert.equal(automationButtons.length, 1, "the workbench sidebar keeps exactly one Automation entry"); |
| 37 | const trashButtons = [...doc.querySelectorAll("button")].filter(button => button.querySelector(".lucide-trash-2")); |
| 38 | assert.equal(trashButtons.length, 1, "the workbench sidebar keeps the Trash entry"); |
| 39 | const searchButtons = [...doc.querySelectorAll("button")].filter(button => button.querySelector(".lucide-search")); |
| 40 | assert.equal(searchButtons.length, 1, "the command-palette search entry moves from the topic bar to the sidebar footer"); |
| 41 | assert.ok(searchButtons[0]?.classList.contains("sidebar__utility-button"), "the search entry occupies a sidebar utility slot"); |
| 42 | assert.equal(doc.querySelectorAll(".sidebar__utility-button").length, 4, "the sidebar footer allocates one slot to search"); |
| 43 | dom.window.close(); |
| 44 | } |
| 45 | console.log("automation regions: shared layout page projection passed"); |
| 46 |