Skip to content

Commit 658e0f8

Browse files
vanceingallsclaude
andcommitted
test(sdk): p2 edge cases — setText no-text-node, override-remove non-existent, flush in smoke
- setText on element with no prior text node (firstTextIdx=-1 path) - applyOverrideSet null removal on non-existent prop is a no-op (no throw) - smoke persist test uses comp.flush() instead of setTimeout - can() JSDoc clarifies Phase 3b false-return is intentional feature-detection Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 131b032 commit 658e0f8

4 files changed

Lines changed: 27 additions & 4 deletions

File tree

packages/sdk/src/engine/mutate.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,17 @@ describe("setText", () => {
140140
expect(serializeDocument(parsed)).toBe(before);
141141
});
142142

143+
it("creates text node when element has no existing text node", () => {
144+
const parsed = parseMutable(
145+
'<div data-hf-id="hf-s" data-hf-root><span data-hf-id="hf-empty"></span></div>',
146+
);
147+
const result = applyOp(parsed, { type: "setText", target: "hf-empty", value: "Added" });
148+
const el = parsed.document.querySelector('[data-hf-id="hf-empty"]');
149+
expect(el?.textContent).toBe("Added");
150+
expect(result.forward[0]?.op).toBe("replace");
151+
expect(result.forward[0]?.value).toBe("Added");
152+
});
153+
143154
it("override-set key maps correctly", () => {
144155
expect(pathToKey("/elements/hf-title/text")).toBe("hf-title.text");
145156
});

packages/sdk/src/session.test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,15 @@ describe("override-set replay on open", () => {
9898
expect(comp.getElement("hf-title")?.inlineStyles["color"]).toBeUndefined();
9999
});
100100

101+
it("null removal override on non-existent property is a safe no-op", async () => {
102+
// backgroundColor doesn't exist on hf-title in the base; removing it must not throw.
103+
const comp = await openComposition(BASE_HTML, {
104+
overrides: { "hf-title.style.backgroundColor": null },
105+
});
106+
expect(comp.getElement("hf-title")).not.toBeNull();
107+
expect(comp.getElement("hf-title")?.inlineStyles["backgroundColor"]).toBeUndefined();
108+
});
109+
101110
it("getOverrides returns the set the session was opened with", async () => {
102111
const overrides = { "hf-title.style.color": "#e63946" };
103112
const comp = await openComposition(BASE_HTML, { overrides });

packages/sdk/src/smoke.test.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -220,9 +220,7 @@ describe("persist adapter", () => {
220220

221221
const comp = await openComposition(BASE_HTML, { persist: adapter });
222222
comp.setStyle("hf-title", { color: "#f00" });
223-
224-
// Give the persist queue a tick to flush
225-
await new Promise((r) => setTimeout(r, 20));
223+
await comp.flush();
226224

227225
expect(writeSpy).toHaveBeenCalled();
228226
const [, content] = writeSpy.mock.calls[0] as [string, string];

packages/sdk/src/types.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,12 @@ export interface Composition {
233233
// ── Advanced / agent layer (F10 layer 2) ──────────────────────────────────
234234
dispatch(op: EditOp, opts?: { origin?: unknown }): void;
235235
batch(fn: () => void, opts?: { origin?: unknown }): void;
236-
/** Dry-run validation — would dispatch(op) succeed? UI enablement, agent precondition checks. */
236+
/**
237+
* Dry-run validation — would dispatch(op) succeed?
238+
* Returns false for: unknown element id, missing root, unimplemented Phase 3b ops, unknown op types.
239+
* Use as a feature-detection gate: `if (!comp.can(op)) return;` — Phase 3b ops always return false
240+
* until the parser-backed engine ships. This is intentional: silent no-op is worse than skipping.
241+
*/
237242
can(op: EditOp): boolean;
238243

239244
// ── Events (one typed emitter — F10) ──────────────────────────────────────

0 commit comments

Comments
 (0)