Frontmatter
| id | 9411 |
| title | TreeGrid Unit Tests (Data & Logic) |
| state | Closed |
| labels | enhancementaitestinggrid |
| assignees | tobiu |
| createdAt | Mar 9, 2026, 12:03 PM |
| updatedAt | Mar 10, 2026, 2:02 PM |
| githubUrl | https://github.com/neomjs/neo/issues/9411 |
| author | tobiu |
| commentsCount | 2 |
| parentIssue | 9404 |
| subIssues | [] |
| subIssuesCompleted | 0 |
| subIssuesTotal | 0 |
| blockedBy | [] |
| blocking | [] |
| closedAt | Mar 10, 2026, 2:02 PM |
TreeGrid Unit Tests (Data & Logic)

Input from Gemini 3.1 Pro:
✦ I have committed the initial test file
test/playwright/unit/data/TreeStore.spec.mjswhich perfectly reproduces the structural mutation bugs we are seeing in theTreeGrid.Here are some hints and specific bugs that need to be explored in the next session based on our latest findings:
- Initial Ingestion Bug: During Store initialization, the projection algorithm is dropping nodes. With the
MainStoretest data, only 6 nodes are rendered initially instead of 7 (child-1-2-2/Row.mjsis completely missing fromstore.items).collectVisibleDescendantsLogic: When collapsing a deeply nested folder (likecomponent), thevisibleDescendantsarray incorrectly gathers root-level siblings (likepackage.jsonandREADME.md) and slices them out of the grid. This suggests the structural maps or the tree traversal loop has a scoping bug.- Row Pool Sizing Bug (
grid.Body): In the demo, the grid initializes 53 row components for only 7 nodes. This completely breaks theitemIndex = i % poolSizerecycling math, causing the "7-click delay" for UI updates becauseupdateContenthits an early-exit condition on the exact same row/record reference.- VDOM invalidation: Once the
TreeStore.spliceand row pooling math are fixed, we still need to ensure thatgrid.Row#updateContentproperly invalidates and re-renders if aRecordmutates internally, even ifforce: falseis passed. Adding alastRecordVersioncheck toupdateContentis likely the fix here.

Input from Gemini 3.1 Pro:
✦ I have successfully implemented the fixes and tests for the
TreeStoredata and logic mechanics.Key Findings & Fixes:
The "Missing Siblings" Bug: When expanding or collapsing nodes, siblings (like
gridwhen expandingcomponent, orREADME.mdwhen collapsingcomponent) were disappearing.
- Root Cause: I traced this down to a critical bug in
Store.hydrateRecord. WhenTreeStore.get(key)was called for a hidden node (not in the visible_itemsarray), it fetched the raw object from#allRecordsMapand correctly calledhydrateRecord. However,hydrateRecordwas unconditionally callingme.map.set(pk, record). This leaked hidden nodes into the activeCollection.map.- Impact: When
TreeStore.splicegenerated thevisibleToAddarray and passed it toCollection.splice,Collection.spliceskipped adding those nodes because!map.has(key)evaluated tofalse(since the hidden node had already bled into the map). This resulted in an emptyaddedItemsarray, silently failing the operation and corrupting the visible list.- Fix: I updated
Store.hydrateRecordto only replace an item inme.mapif it already exists in the map (if (me.map.has(pk))). This prevents hidden/filtered items from bleeding into the active collection state during "Soft Hydration".Turbo Mode / Soft Hydration (
autoInitRecords: false):
- In Turbo Mode, the
grid.Rowexpects properties likedepth,isLeaf,collapsed,siblingCount, andsiblingIndexto be available directly on the raw data objects.- I updated
TreeStore.spliceto actively perform Soft Hydration during ingestion. If raw data objects are missingdepth,isLeaf, orcollapsed, it computes and injects them directly (e.g.depth = parent.depth + 1).siblingCountandsiblingIndexwere already being handled correctly viaupdateSiblingStats(), which mutates the raw objects.Unit Tests Added: I expanded
test/playwright/unit/data/TreeStore.spec.mjsto comprehensively cover these scenarios:
should only remove visible descendants on collapse, not siblings: Verifies the fix for theStore.hydrateRecordmap bleed bug.singleExpand mode should collapse siblings when a node is expanded: Verifies the correct interaction ofsingleExpandwhen sibling nodes are toggled.#childrenMap and #allRecordsMap caching logic: Verifies O(1) accessibility for both visible and hidden nodes.siblingCount and siblingIndex are correctly resolved for raw data objects: Verifies the Turbo Mode (Soft Hydration) logic successfully computes and assigns all hierarchical metadata (depth,isLeaf,collapsed,siblingCount,siblingIndex) to raw JSON objects without instantiating full Records.All 4 tests are passing! I have committed the changes and will close this issue now.
Goal
Ensure the core logic of the
TreeStoreandTreeModelis robust and handles hierarchical data operations deterministically using the Playwright unit testing environment.Details
TreeStoreflattening logic: Ensure that expanding/collapsing nodes correctly updates the visible array of records.#childrenMapcaching: Verify that O(1) lookups return correct child nodes.singleExpandmode logic.depth,isLeaf,siblingCount, andsiblingIndexare correctly resolved for raw data objects whenautoInitRecords: falseis used (Turbo Mode).test/playwright/unit/data/TreeStore.spec.mjs.