Skip to content

test(runner): the batched drop is one commit, and stays one (DEV-2500) - #199

Open
danielzytohoc wants to merge 1 commit into
masterfrom
test/DEV-2500-batched-drop
Open

test(runner): the batched drop is one commit, and stays one (DEV-2500)#199
danielzytohoc wants to merge 1 commit into
masterfrom
test/DEV-2500-batched-drop

Conversation

@danielzytohoc

@danielzytohoc danielzytohoc commented Aug 17, 2026

Copy link
Copy Markdown

Closes audit gap G3 (DEV-2500 item h): the batched addFiles contract was untested.

DEV-2500's ticket calls the batched onAddFiles necessary, not cosmetic: N sequential addFile calls would mean N setFiles renders and, on a Tier-2 framework, N container pushes each invalidating the last. Until now that contract survived only as a code comment above addFiles — a naive per-file loop would have passed the entire suite, because the multi-file drop e2e only checks that the rows appear.

The extraction (behavior-identical)

The map transform moves out of App.tsx's addFiles into apps/authoring/src/addFiles.ts as applyDroppedFiles(current, dropped) — dependency-free like demoOwners.ts and markdownActions.ts, so the pipeline tests can import it under --experimental-strip-types (its one import is type-only, which the stripper erases). The empty-drop guard becomes "returns current reference-equal", which App.tsx compares against to skip the commit — the same early return as before, now observable. Every side effect stays in App.tsx where it was: the ref commit, the render, the variadic markDirty, the per-file runtime writes, the container syncing feedback.

The new unit contract

pipeline/add-files.test.mjs (node --test, markdown-actions.test.mjs conventions):

  • a drop lands as one new files map, not N — one call returns ONE new map carrying every existing and dropped file; the input object is untouched (asserted against a snapshot).
  • a colliding path is overwritten in place — by the time a batch reaches the helper, FileTree.commit() has already asked ("Overwrite" vs "Keep both") and "Keep both" renamed before the call; a collision arriving here means overwrite.
  • an empty drop returns the same map — reference-equal, so the caller skips the commit.

The source guard

The same spec slices addFiles out of App.tsx (balanced-paren scan; the fragility is noted honestly and hedged with sanity assertions that fail loudly if the scan breaks) and holds it to the one-commit shape: setFiles( exactly once, one filesRef.current assignment, the map built via applyDroppedFiles. Mutation-checked: temporarily adding a second setFiles( call inside addFiles fails the test.

Verification

  • pnpm typecheck green, pnpm test green (413 tests, 4 new)
  • pnpm build + pnpm --filter @handsontable/demo-authoring build green
  • pnpm e2e e2e/files-drop.spec.ts — all 10 drop e2e tests pass

Note: this PR touches product code (the extraction in App.tsx + the new addFiles.ts), not only tests — kept as its own PR per the repo owner's review preference.


Note

Low Risk
Behavior-preserving refactor with new unit and source-structure tests; no API or auth changes.

Overview
Closes audit gap G3: the batched drag-and-drop path (onAddFiles / DEV-2500) was only documented in comments—N per-file addFile calls would still pass e2e.

The workspace map merge moves into applyDroppedFiles in addFiles.ts (pure, importable under pipeline tests). App.tsx addFiles delegates to it, skips commit when the result is reference-equal to filesRef.current (empty drop), and still does one setFiles, one ref assignment, dirty dots, runtime writes, and container syncing.

pipeline/add-files.test.mjs covers the helper (one new map, overwrite on collision, empty → same reference) and greps addFiles in App.tsx for exactly one setFiles and one filesRef assignment via applyDroppedFiles.

Reviewed by Cursor Bugbot for commit 6cb9eb8. Bugbot is set up for automated code reviews on this repo. Configure here.

Closes audit gap G3 (DEV-2500 item h): the batched addFiles contract was
untested. The ticket calls the batched onAddFiles necessary, not cosmetic —
N sequential addFile calls would mean N setFiles renders and, on a Tier-2
framework, N container pushes each invalidating the last — yet until now
that contract survived only as a code comment above addFiles. A regression
to a per-file loop would have passed the whole suite: the multi-file drop
e2e only checks that the rows appear.

Three pieces:

- The map transform moves out of App.tsx's addFiles into
  apps/authoring/src/addFiles.ts as applyDroppedFiles(current, dropped) —
  behavior-identical, dependency-free like demoOwners.ts and
  markdownActions.ts so the pipeline tests can import it under
  --experimental-strip-types. The empty-drop guard becomes "returns
  current reference-equal", which App.tsx compares against to skip the
  commit — the same early return as before, now observable.

- pipeline/add-files.test.mjs pins the contract: one drop returns ONE new
  map with every file (input untouched), a colliding path overwrites in
  place (the FILES tree has already asked before the batch gets here), an
  empty drop returns the same map.

- A source grep in the same spec slices addFiles out of App.tsx
  (balanced-paren scan, fragility noted honestly and hedged with sanity
  assertions) and holds it to the one-commit shape: setFiles exactly once,
  one filesRef assignment, the map built via applyDroppedFiles. Verified
  it bites: a second setFiles call fails the test.

App.tsx keeps every side effect where it was: the ref commit, the render,
the variadic markDirty, the per-file runtime writes, the container syncing
feedback.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant