Skip to content

Commit 2d979a0

Browse files
committed
test: add failing tests for array iteration change tracking
These tests reproduce the bug where modifications to array items retrieved via iteration methods (find(), forEach, for...of) are not tracked by the change proxy. Root cause: When using array iteration methods like find(), the proxy returns raw array elements instead of proxied versions. This causes mutations to these elements to not be tracked, resulting in getChanges() returning an empty object. This directly causes the createOptimisticAction bug where mutationFn is never called when modifying nested array items via: draft.nested.array.find(...).property = value Failing tests: - find() returns unproxied items - forEach() iterates over unproxied items - for...of iterates over unproxied items Working test: - Direct index access [0] works because the proxy's get handler intercepts numeric index access and returns proxied items The fix requires handling array iteration methods similar to how Map/Set iteration is already handled in the proxy.
1 parent e19afbd commit 2d979a0

1 file changed

Lines changed: 83 additions & 0 deletions

File tree

packages/db/tests/proxy.test.ts

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1653,5 +1653,88 @@ describe(`Proxy Library`, () => {
16531653
})
16541654
expect(obj.date).toEqual(originalDate)
16551655
})
1656+
1657+
// BUG: Array.find() returns unproxied items, so changes to them aren't tracked
1658+
// This is the root cause of the createOptimisticAction bug where mutationFn
1659+
// is never called when modifying nested array items via .find()
1660+
it(`should track changes when modifying array items retrieved via find()`, () => {
1661+
const obj = {
1662+
job: {
1663+
orders: [
1664+
{ orderId: `order-1`, orderBinInt: 1 },
1665+
{ orderId: `order-2`, orderBinInt: 2 },
1666+
],
1667+
},
1668+
}
1669+
const { proxy, getChanges } = createChangeProxy(obj)
1670+
1671+
// This is the exact pattern from the user's reproduction:
1672+
// Using .find() to get an array item and then modifying it
1673+
const order = proxy.job.orders.find(
1674+
(order) => order.orderId === `order-1`
1675+
)
1676+
if (order) {
1677+
order.orderBinInt = 99
1678+
}
1679+
1680+
// The changes should be tracked - this currently fails
1681+
const changes = getChanges()
1682+
expect(Object.keys(changes).length).toBeGreaterThan(0)
1683+
expect(changes.job?.orders?.[0]?.orderBinInt).toBe(99)
1684+
})
1685+
1686+
// Additional tests for other array iteration methods that should track changes
1687+
it(`should track changes when modifying array items via forEach`, () => {
1688+
const obj = {
1689+
items: [
1690+
{ id: 1, value: 10 },
1691+
{ id: 2, value: 20 },
1692+
],
1693+
}
1694+
const { proxy, getChanges } = createChangeProxy(obj)
1695+
1696+
proxy.items.forEach((item) => {
1697+
item.value = item.value * 2
1698+
})
1699+
1700+
const changes = getChanges()
1701+
expect(Object.keys(changes).length).toBeGreaterThan(0)
1702+
})
1703+
1704+
it(`should track changes when modifying array items via for...of`, () => {
1705+
const obj = {
1706+
items: [
1707+
{ id: 1, value: 10 },
1708+
{ id: 2, value: 20 },
1709+
],
1710+
}
1711+
const { proxy, getChanges } = createChangeProxy(obj)
1712+
1713+
for (const item of proxy.items) {
1714+
item.value = item.value * 2
1715+
}
1716+
1717+
const changes = getChanges()
1718+
expect(Object.keys(changes).length).toBeGreaterThan(0)
1719+
})
1720+
1721+
it(`should track changes when modifying array items via index access`, () => {
1722+
const obj = {
1723+
items: [
1724+
{ id: 1, value: 10 },
1725+
{ id: 2, value: 20 },
1726+
],
1727+
}
1728+
const { proxy, getChanges } = createChangeProxy(obj)
1729+
1730+
// Direct index access should work
1731+
const firstItem = proxy.items[0]
1732+
if (firstItem) {
1733+
firstItem.value = 100
1734+
}
1735+
1736+
const changes = getChanges()
1737+
expect(Object.keys(changes).length).toBeGreaterThan(0)
1738+
})
16561739
})
16571740
})

0 commit comments

Comments
 (0)