mirror of
https://github.com/webstudio-is/webstudio.git
synced 2026-10-30 00:27:43 +09:00
This PR expands Webstudio MCP and CLI into a more complete agent authoring interface. Agents can discover project capabilities, edit real Webstudio content, use data/resources, verify visual output, and report useful issues when workflows fail. ## MCP User Capabilities - Create, update, duplicate, reorder, and delete pages. - Create pages from templates and manage reusable page templates. - Inspect project pages, instances, props, styles, assets, variables, resources, and metadata. - Insert Webstudio components and authored JSX fragments into pages. - Edit text, props, styles, breakpoints, design tokens, and CSS variables. - Update page metadata, SEO fields, redirects, marketplace metadata, and project settings. - Create and use static data variables. - Create and use dynamic resources fetched over HTTP. - Use REST, GraphQL, and built-in system resources in authored pages. - Bind data variables and resources to visible page content. - Create resource-backed pages such as sitemap XML, structured SEO data, and API-driven content sections. - Preview current project state without requiring a publish step. - Capture screenshots for visual verification. - Verify responsive designs across desktop, tablet, and mobile breakpoints. - Use screenshot diff and OCR-style checks to inspect rendered output. - Reset and refresh local MCP project state when needed. - Discover available CLI/MCP commands from generated manuals. - Use clearer examples for resources, data variables, JSX authoring, previewing, and visual checks. - Read marketplace product metadata without requiring a full project snapshot. - Get safer guidance when using low-level patch tools. - Get a ready-to-copy Discord report template when MCP/CLI behavior is confusing or broken.
92 lines
2.7 KiB
TypeScript
92 lines
2.7 KiB
TypeScript
import { describe, expect, test } from "vitest";
|
|
import { createDefaultPages } from "@webstudio-is/project-build";
|
|
import { $, renderData } from "@webstudio-is/template";
|
|
import { buildInstancePath } from "./lookup";
|
|
|
|
describe("buildInstancePath", () => {
|
|
const createPages = () =>
|
|
createDefaultPages({
|
|
homePageId: "homePageId",
|
|
rootInstanceId: "rootId",
|
|
systemDataSourceId: "systemId",
|
|
});
|
|
|
|
test("returns empty array when instance has no selector", () => {
|
|
const pages = createPages();
|
|
const instances = new Map();
|
|
|
|
const result = buildInstancePath("nonexistent", pages, instances);
|
|
expect(result).toEqual([]);
|
|
});
|
|
|
|
test("returns empty array for root instance (no ancestors)", () => {
|
|
const { instances } = renderData(
|
|
<$.Body ws:id="rootId">
|
|
<$.Box ws:id="boxId"></$.Box>
|
|
</$.Body>
|
|
);
|
|
const pages = createPages();
|
|
|
|
const result = buildInstancePath("rootId", pages, instances);
|
|
expect(result).toEqual([]);
|
|
});
|
|
|
|
test("builds path for single-level nesting", () => {
|
|
const { instances } = renderData(
|
|
<$.Body ws:id="rootId">
|
|
<$.Box ws:id="boxId"></$.Box>
|
|
</$.Body>
|
|
);
|
|
const pages = createPages();
|
|
|
|
const result = buildInstancePath("boxId", pages, instances);
|
|
expect(result).toEqual(["Body"]);
|
|
});
|
|
|
|
test("builds path for multi-level nesting", () => {
|
|
const { instances } = renderData(
|
|
<$.Body ws:id="rootId">
|
|
<$.Box ws:id="containerId">
|
|
<$.Heading ws:id="headingId"></$.Heading>
|
|
</$.Box>
|
|
</$.Body>
|
|
);
|
|
const pages = createPages();
|
|
|
|
const result = buildInstancePath("headingId", pages, instances);
|
|
expect(result).toEqual(["Body", "Box"]);
|
|
});
|
|
|
|
test("builds path for deeply nested instance", () => {
|
|
const { instances } = renderData(
|
|
<$.Body ws:id="rootId">
|
|
<$.Box ws:id="sectionId">
|
|
<$.Box ws:id="articleId">
|
|
<$.Box ws:id="divId">
|
|
<$.Text ws:id="textId"></$.Text>
|
|
</$.Box>
|
|
</$.Box>
|
|
</$.Box>
|
|
</$.Body>
|
|
);
|
|
const pages = createPages();
|
|
|
|
const result = buildInstancePath("textId", pages, instances);
|
|
expect(result).toEqual(["Body", "Box", "Box", "Box"]);
|
|
});
|
|
|
|
test("handles instances with custom labels", () => {
|
|
const { instances } = renderData(
|
|
<$.Body ws:id="rootId" ws:label="Main Body">
|
|
<$.Box ws:id="navId" ws:label="Navigation">
|
|
<$.Link ws:id="linkId" ws:label="Home Link"></$.Link>
|
|
</$.Box>
|
|
</$.Body>
|
|
);
|
|
const pages = createPages();
|
|
|
|
const result = buildInstancePath("linkId", pages, instances);
|
|
expect(result).toEqual(["Main Body", "Navigation"]);
|
|
});
|
|
});
|