// @vitest-environment node import { readdir, readFile } from "node:fs/promises"; import path from "node:path"; import { describe, expect, it } from "vitest"; const sourceRoot = path.resolve(import.meta.dirname, ".."); async function productionTypeScriptFiles(dir = sourceRoot): Promise { const entries = await readdir(dir, { withFileTypes: true }); const files = await Promise.all( entries.map(async (entry) => { const filePath = path.join(dir, entry.name); if (entry.isDirectory()) { return productionTypeScriptFiles(filePath); } if (!entry.name.endsWith(".ts") || entry.name.includes(".test.")) { return []; } return [filePath]; }), ); return files.flat(); } async function matchingFiles(pattern: RegExp): Promise { const matches: string[] = []; for (const filePath of await productionTypeScriptFiles()) { if (pattern.test(await readFile(filePath, "utf8"))) { matches.push(path.relative(sourceRoot, filePath)); } } return matches.toSorted(); } describe("Web Awesome control ownership", () => { it("keeps dialogs, menus, and tabs on shared primitives", async () => { expect(await matchingFiles(/]*\srole=["'](?:menu|menubar|menuitem|tab|tablist)["']/u), ).toEqual([]); expect( await matchingFiles(/]*class=["'][^"']*(?:menu|select|popover|dropdown)/u), ).toEqual([ "pages/chat/components/chat-effort-picker.ts", "pages/chat/components/chat-model-picker.ts", ]); }); it("limits custom comboboxes to dynamic suggestion surfaces", async () => { // Web Awesome Core has no combobox; its combobox is a paid Pro component. // This inventory tracks literal ARIA roles, not Web Awesome elements that own roles internally. expect(await matchingFiles(/<[a-z][^>]*\srole=["'](?:combobox|listbox|option)["']/u)).toEqual([ "components/command-palette.ts", "pages/chat/components/chat-composer-skill-menu.ts", "pages/chat/components/chat-composer-slash-menu.ts", "pages/chat/components/chat-model-picker-options.ts", "pages/chat/components/chat-model-picker.ts", ]); }); it("limits custom dividers to docked multi-pane layouts", async () => { // Web Awesome split panel owns exactly two panes; these layouts coordinate // sidebar, inspector, and responsive dock state across more than two panes. expect(await matchingFiles(/