diff --git a/__tests__/array-methods-filter-length.js b/__tests__/array-methods-filter-length.js new file mode 100644 index 00000000..a52f3763 --- /dev/null +++ b/__tests__/array-methods-filter-length.js @@ -0,0 +1,32 @@ +import {Immer, enableArrayMethods} from "../src/immer" +import {clearPlugin, PluginArrayMethods} from "../src/internal" + +for (const enabled of [false, true]) { + for (const autoFreeze of [false, true]) { + describe(`filter length: plugin=${enabled}, autoFreeze=${autoFreeze}`, () => { + beforeEach(() => { + if (enabled) enableArrayMethods() + else clearPlugin(PluginArrayMethods) + }) + afterEach(() => clearPlugin(PluginArrayMethods)) + + test("does not visit items appended by the predicate", () => { + const {produce} = new Immer({autoFreeze}) + const base = [1, 2] + const visited = [] + const result = produce(base, draft => { + draft.push(3) + const filtered = draft.filter((value, index) => { + visited.push(index) + if (index === 0) draft.push(4) + return true + }) + expect(filtered).toEqual([1, 2, 3]) + }) + expect(visited).toEqual([0, 1, 2]) + expect(result).toEqual([1, 2, 3, 4]) + expect(base).toEqual([1, 2]) + }) + }) + } +} diff --git a/src/plugins/arrayMethods.ts b/src/plugins/arrayMethods.ts index b8a96a68..a4cad6b5 100644 --- a/src/plugins/arrayMethods.ts +++ b/src/plugins/arrayMethods.ts @@ -451,7 +451,8 @@ export function enableArrayMethods() { const result: any[] = [] // First pass: call predicate on base values to determine which items pass - for (let i = 0; i < source.length; i++) { + const length = source.length + for (let i = 0; i < length; i++) { if (predicate.call(thisArg, source[i], i, source)) { // Only create draft for items that passed the predicate result.push(state.draft_[i])