بنقرة واحدة
eney-test
Add and run tests for an Eney MCP skill using the UIX test session API and node:test.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Add and run tests for an Eney MCP skill using the UIX test session API and node:test.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
Create a new Eney MCP skill using the CLI scaffolding tool, then implement widget components with Eney UIX.
Reference documentation for Eney UIX widgets and UI generation. Covers Form, Paper, Actions, and all components for building native macOS UIs in MCP extensions.
Set up SSH key commit signing for Git and GitHub so all commits (including those made via Claude Code) are cryptographically verified.
Build an Eney MCP skill, deploy it locally, launch it in the Eney app via deeplink, and iterate on issues with the user.
استنادا إلى تصنيف SOC المهني
| name | eney-test |
| description | Add and run tests for an Eney MCP skill using the UIX test session API and node:test. |
| metadata | {"author":"macpaw","version":"1.0"} |
Add widget and unit tests to an MCP extension using @eney/api/testing and node:test.
Determine which MCP to test — ask the user or infer from the current directory. Read its components:
ls extensions/<mcp-name>/components/
Newly scaffolded MCPs already include the test script, @types/node in tsconfig, and a tests/ directory. Verify this before proceeding — only add missing pieces:
package.json: should have "test": "npx tsx --test tests/*.test.ts" in scripts. Add if missing.tsconfig.json: should have "types": ["@types/react", "@types/node"] in compilerOptions. Add if missing.@types/node: should be in devDependencies. Install if missing: npm install --save-dev @types/nodeCreate test files in a tests/ directory inside the MCP.
createUIXTestSession)Use createUIXTestSession from @eney/api/testing to mount a widget definition and interact with it:
import { describe, it } from "node:test";
import assert from "node:assert/strict";
import { createUIXTestSession } from "@eney/api/testing";
import MyWidget from "../components/my-widget.js";
describe("MyWidget", () => {
it("renders with default props", async () => {
const session = await createUIXTestSession(MyWidget);
const state = session.getSimplifiedState();
const form = state.children?.find((c) => c.type === "form");
assert.ok(form, "should render a form");
session.unmount();
});
});
createUIXTestSession APIcreateUIXTestSession(widgetComponent, props?) returns a UIXTestSession:
| Method | Description |
|---|---|
getState() | Returns the full widget tree (Widget) |
getSimplifiedState() | Returns a simplified tree (type, id, flat props, children) |
findWidget(query) | Find first widget matching { type?, name?, label?, title?, $id? } |
findAllWidgets(query) | Find all widgets matching a query |
sendEvent(widgetId, properties?) | Send a raw event to a widget by $id |
click(widget) | Click a widget (Action, SubmitForm button) |
type(widget, text) | Type text into a TextField/PasswordField |
check(widget, value?) | Toggle a Checkbox (defaults to true) |
select(widget, value) | Select a Dropdown option |
setNumber(widget, value) | Set a NumberField value |
unmount() | Unmount the component — always call at the end of each test |
closedWith | The string passed to closeWidget(), or null |
widget parameters accept either a Widget object (from findWidget) or a string $id.
Use findWidget to locate widgets by property:
// By name (matches Form field `name` prop)
session.findWidget({ name: "password" });
// By title (matches Action/SubmitForm `title` prop)
session.findWidget({ title: "Done" });
// By type (with or without "widget:" prefix)
session.findWidget({ type: "checkbox" });
// By label
session.findWidget({ label: "Include numbers" });
Widget properties are in widget.properties. Form field values are typically at .properties.value (not .properties.checked for checkboxes):
const field = session.findWidget({ name: "email" });
const value = String(field!.properties.value ?? "");
When a component calls closeWidget(text), the session captures it:
await session.click(doneBtn!);
assert.equal(session.closedWith, "Expected close message");
Test business logic (helpers, generators, parsers) separately without the widget framework:
import { describe, it } from "node:test";
import assert from "node:assert/strict";
import { generatePassword } from "../components/generate-password.js";
describe("generatePassword", () => {
it("generates password of requested length", () => {
const password = generatePassword({
length: 20,
symbols: true,
numbers: true,
});
assert.equal(password.length, 20);
});
});
cd extensions/<mcp-name> && npm test
Fix any failures before proceeding.
Tests should not break the build. Confirm:
cd extensions/<mcp-name> && npm run build
| Problem | Cause | Fix |
|---|---|---|
Cannot find module 'node:test' | Missing @types/node | npm i -D @types/node and add to tsconfig types |
| Test files compiled to dist | Tests not excluded from build | Exclude tests directory in tsconfig or keep tests inside tests/ which is naturally outside rootDir patterns |
Widget null from findWidget | Wrong query property | Check widget tree with getSimplifiedState() to see actual types and properties |
Checkbox value is undefined | Using .properties.checked | Use .properties.value instead — checkboxes serialize checked as value in the widget tree |
Detected multiple renderers warning | React context warning from test isolation | Safe to ignore — does not affect test results |
| Import errors in test files | Missing .js extension | Use .js extensions for local imports (ESM requirement) |
@types/node in devDependencies@types/node in tsconfig types array"test" script in package.jsontests/ directorycreateUIXTestSessioncloseWidget behavior testedsession.unmount() called at end of every testnpm test passesnpm run build still passes