molecule-core/canvas
Hongming Wang 39eb3eb2e4 test(canvas): unit tests for OrgCancelButton — cascade-delete + optimistic store (#2071)
[Molecule-Platform-Evolvement-Manager]

Closes the third item from #2071 (Canvas test gaps follow-up). Builds
on the A2AEdge tests in PR #2143.

10 cases across 4 buckets:

**Render (2):**
- Default pill with `Cancel (N)` text + correct ARIA label
- Confirm dialog NOT visible until pill click

**Pill click (3):**
- Click flips to confirming view + stops propagation (so React Flow
  doesn't interpret the click as a node selection)
- Confirm copy pluralizes correctly: count=1 → "Delete 1 workspace?",
  count>1 → "Delete N workspaces?". Negative assertion guards against
  the wrong-form regressing in either direction.

**No / cancel-confirm (1):**
- Click No → returns to pill, no API call, no store mutation

**Yes / cascade-delete (4):**
- Happy path: beginDelete locks the WHOLE subtree (root + children,
  NOT unrelated workspace) → api.del("/workspaces/<id>?confirm=true")
  → optimistic store filter strips subtree, keeps unrelated → success
  toast → endDelete in finally
- WS-event race: WS_REMOVED handler clears the root mid-flight. The
  bail-out branch (`!postDeleteState.nodes.some(n => n.id === rootId)`)
  must NOT then run a second optimistic filter. Pre-fix the post-await
  subtree walk would miss any orphaned descendants whose parentId got
  reparented upward by handleCanvasEvent — pinned now.
- Error path: api.del rejects → endDelete UNDOes the lock + error
  toast surfaces the message → subtree STAYS in the store so the user
  can retry / interact with the still-deploying nodes
- Non-Error rejection (e.g. string thrown directly): toast surfaces
  the canned "Cancel failed" fallback instead of attempting `.message`

## Mocking

- `@/lib/api`, `@/components/Toaster`: simple spy mocks
- `@/store/canvas`: object that satisfies BOTH the selector pattern
  (`useCanvasStore(s => s.x)`) AND `getState()` / `setState()` since
  the cascade-delete handler walks the subtree via `getState()` and
  mutates via `setState()` for the optimistic removal. `vi.hoisted`
  preserves referential identity so the mock fns wired into the
  state object are observed by every consumer.

## Test plan

- [x] All 10 cases pass locally (`vitest run OrgCancelButton.test.tsx` — ~990ms)
- [x] No changes to the SUT — pure additive coverage
- [ ] CI green

## #2071 progress after this PR

- [x] useTemplateDeploy (PR #2121)
- [x] A2AEdge (PR #2143)
- [x] OrgCancelButton (this PR)
- [ ] useDragHandlers — separate PR

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 23:38:59 -07:00
..
e2e chore(simplify): trim SHA-rot comments + harden TENANT_HOST scheme/port stripping 2026-04-26 11:44:54 -07:00
public chore: replace brand icon and add HANDOFF.md 2026-04-13 13:03:40 -07:00
src test(canvas): unit tests for OrgCancelButton — cascade-delete + optimistic store (#2071) 2026-04-26 23:38:59 -07:00
.env.example fix(canvas): close 4 gaps in WS status indicator (env, toast, tests) 2026-04-14 08:26:38 +00:00
.gitignore feat(canvas): SaaS cross-origin — slug header + cookie credentials (Phase F) 2026-04-14 20:08:39 -07:00
components.json chore(canvas): initialize shadcn/ui — components.json + cn utility 2026-04-18 07:57:17 -07:00
Dockerfile chore(canvas): upgrade node:20-alpine → node:22-alpine 2026-04-24 18:54:30 +00:00
next.config.ts fix(canvas,dotenv): review-driven hardening of fit gate + parser parity 2026-04-24 22:23:51 -07:00
package-lock.json fix(canvas): cascade-delete UX — require checkbox before Delete All (#1314) 2026-04-21 07:06:45 +00:00
package.json fix(quickstart): make README cp-paste flow bugless end-to-end (#1871) 2026-04-23 19:53:43 +00:00
playwright.config.ts initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
playwright.staging.config.ts feat(e2e): canary + canvas Playwright workflows; delegation mechanics 2026-04-21 04:15:10 -07:00
postcss.config.js initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
tailwind.config.ts initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
tsconfig.json initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
vitest.config.ts initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00