@shopify/flash-list
Version:
FlashList is a more performant FlatList replacement
575 lines (520 loc) • 22.6 kB
text/typescript
import { RenderStackManager } from "../recyclerview/RenderStackManager";
import { ConsecutiveNumbers } from "../recyclerview/helpers/ConsecutiveNumbers";
const mock1Data = [
{ id: 1, name: "Item 1", itemType: "type1" },
{ id: 2, name: "Item 2", itemType: "type2" },
{ id: 3, name: "Item 3", itemType: "type1" },
{ id: 4, name: "Item 4", itemType: "type2" },
{ id: 5, name: "Item 5", itemType: "type1" },
{ id: 6, name: "Item 6", itemType: "type2" },
{ id: 7, name: "Item 7", itemType: "type1" },
{ id: 8, name: "Item 8", itemType: "type2" },
{ id: 9, name: "Item 9", itemType: "type1" },
{ id: 10, name: "Item 10", itemType: "type2" },
{ id: 11, name: "Item 11", itemType: "type1" },
];
const mock1 = {
data: mock1Data,
getStableId: (index: number) => mock1Data[index].id.toString(),
getItemType: (index: number) => mock1Data[index].itemType,
length: mock1Data.length,
};
const mock2Data = [
{ id: 5, name: "Item 1", itemType: "type1" },
{ id: 6, name: "Item 2", itemType: "type2" },
{ id: 7, name: "Item 3", itemType: "type1" },
{ id: 8, name: "Item 4", itemType: "type2" },
{ id: 9, name: "Item 5", itemType: "type1" },
{ id: 10, name: "Item 6", itemType: "type2" },
{ id: 11, name: "Item 7", itemType: "type1" },
{ id: 12, name: "Item 8", itemType: "type2" },
{ id: 13, name: "Item 9", itemType: "type1" },
{ id: 14, name: "Item 10", itemType: "type2" },
{ id: 15, name: "Item 11", itemType: "type1" },
];
const mock2 = {
data: mock2Data,
getStableId: (index: number) => mock2Data[index].id.toString(),
getItemType: (index: number) => mock2Data[index].itemType,
length: mock2Data.length,
};
const mock3Data = [
{ id: 1, name: "Item 1", itemType: "type1" },
{ id: 2, name: "Item 2", itemType: "type1" },
{ id: 3, name: "Item 3", itemType: "type1" },
{ id: 4, name: "Item 4", itemType: "type1" },
{ id: 5, name: "Item 5", itemType: "type1" },
{ id: 6, name: "Item 6", itemType: "type1" },
{ id: 7, name: "Item 7", itemType: "type1" },
{ id: 8, name: "Item 8", itemType: "type1" },
{ id: 9, name: "Item 9", itemType: "type1" },
{ id: 10, name: "Item 10", itemType: "type1" },
{ id: 11, name: "Item 11", itemType: "type1" },
{ id: 12, name: "Item 12", itemType: "type1" },
{ id: 13, name: "Item 13", itemType: "type1" },
{ id: 14, name: "Item 14", itemType: "type1" },
{ id: 15, name: "Item 15", itemType: "type1" },
];
const mock3 = {
data: mock3Data,
getStableId: (index: number) => mock3Data[index].id.toString(),
getItemType: (index: number) => mock3Data[index].itemType,
length: mock3Data.length,
};
const mock4Data = [
{ id: 1, name: "Item 1", itemType: "type1" },
{ id: 2, name: "Item 2", itemType: "type1" },
{ id: 3, name: "Item 3", itemType: "type1" },
{ id: 4, name: "Item 4", itemType: "type1" },
{ id: 5, name: "Item 5", itemType: "type1" },
{ id: 6, name: "Item 6", itemType: "type1" },
{ id: 7, name: "Item 7", itemType: "type1" },
{ id: 8, name: "Item 8", itemType: "type2" },
{ id: 9, name: "Item 9", itemType: "type2" },
{ id: 10, name: "Item 10", itemType: "type2" },
{ id: 11, name: "Item 11", itemType: "type2" },
{ id: 12, name: "Item 12", itemType: "type2" },
{ id: 13, name: "Item 13", itemType: "type2" },
{ id: 14, name: "Item 14", itemType: "type2" },
{ id: 15, name: "Item 15", itemType: "type2" },
];
const mock4 = {
data: mock4Data,
getStableId: (index: number) => mock4Data[index].id.toString(),
getItemType: (index: number) => mock4Data[index].itemType,
length: mock4Data.length,
};
const mock5Data = [
{ id: 1, name: "Item 1", itemType: "type2" },
{ id: 2, name: "Item 2", itemType: "type2" },
{ id: 3, name: "Item 3", itemType: "type2" },
{ id: 4, name: "Item 4", itemType: "type2" },
{ id: 5, name: "Item 5", itemType: "type2" },
{ id: 6, name: "Item 6", itemType: "type2" },
{ id: 7, name: "Item 7", itemType: "type2" },
{ id: 8, name: "Item 8", itemType: "type1" },
{ id: 9, name: "Item 9", itemType: "type1" },
{ id: 10, name: "Item 10", itemType: "type1" },
{ id: 11, name: "Item 11", itemType: "type1" },
{ id: 12, name: "Item 12", itemType: "type1" },
{ id: 13, name: "Item 13", itemType: "type1" },
{ id: 14, name: "Item 14", itemType: "type1" },
{ id: 15, name: "Item 15", itemType: "type1" },
];
const mock5 = {
data: mock5Data,
getStableId: (index: number) => mock5Data[index].id.toString(),
getItemType: (index: number) => mock5Data[index].itemType,
length: mock5Data.length,
};
const mock6Data = [
{ id: 0, name: "Item 0", itemType: "type1" },
{ id: 1, name: "Item 1", itemType: "type1" },
{ id: 2, name: "Item 2", itemType: "type1" },
{ id: 3, name: "Item 3", itemType: "type1" },
{ id: 4, name: "Item 4", itemType: "type1" },
{ id: 5, name: "Item 5", itemType: "type1" },
{ id: 6, name: "Item 6", itemType: "type1" },
{ id: 7, name: "Item 7", itemType: "type1" },
];
const mock6 = {
data: mock6Data,
getStableId: (index: number) => mock6Data[index].id.toString(),
getItemType: (index: number) => mock6Data[index].itemType,
length: mock6Data.length,
};
const mock7Data = [
{ id: 0, name: "Item 0", itemType: "type1" },
{ id: 2, name: "Item 2", itemType: "type1" },
{ id: 3, name: "Item 3", itemType: "type1" },
{ id: 4, name: "Item 4", itemType: "type1" },
{ id: 5, name: "Item 5", itemType: "type1" },
{ id: 6, name: "Item 6", itemType: "type1" },
{ id: 7, name: "Item 7", itemType: "type1" },
{ id: 8, name: "Item 8", itemType: "type1" },
];
const mock7 = {
data: mock7Data,
getStableId: (index: number) => mock7Data[index].id.toString(),
getItemType: (index: number) => mock7Data[index].itemType,
length: mock7Data.length,
};
const mock8Data = [
{ id: 16, name: "Item 16", itemType: "type1" },
{ id: 17, name: "Item 17", itemType: "type1" },
{ id: 18, name: "Item 18", itemType: "type1" },
{ id: 19, name: "Item 19", itemType: "type1" },
{ id: 20, name: "Item 20", itemType: "type1" },
{ id: 1, name: "Item 1", itemType: "type1" },
{ id: 2, name: "Item 2", itemType: "type1" },
{ id: 3, name: "Item 3", itemType: "type1" },
{ id: 4, name: "Item 4", itemType: "type1" },
{ id: 5, name: "Item 5", itemType: "type1" },
{ id: 6, name: "Item 6", itemType: "type1" },
{ id: 7, name: "Item 7", itemType: "type1" },
{ id: 8, name: "Item 8", itemType: "type1" },
{ id: 9, name: "Item 9", itemType: "type1" },
{ id: 10, name: "Item 10", itemType: "type1" },
{ id: 11, name: "Item 11", itemType: "type1" },
{ id: 12, name: "Item 12", itemType: "type1" },
{ id: 13, name: "Item 13", itemType: "type1" },
{ id: 14, name: "Item 14", itemType: "type1" },
{ id: 15, name: "Item 15", itemType: "type1" },
];
const mock8 = {
data: mock8Data,
getStableId: (index: number) => mock8Data[index].id.toString(),
getItemType: (index: number) => mock8Data[index].itemType,
length: mock8Data.length,
};
// Helper to create mock data structures
const createMockData = (
items: { id: string | number; itemType: string; name?: string }[]
) => {
return {
data: items.map((item) => ({
...item,
name: item.name || `Item ${item.id}`,
})),
getStableId: (index: number) => items[index].id.toString(),
getItemType: (index: number) => items[index].itemType,
length: items.length,
};
};
// Helper to run sync and get sorted keys from the entire keyMap
const runSyncAndGetEntireKeyMapKeys = (
manager: RenderStackManager,
mock: {
data: any[];
getStableId: (index: number) => string;
getItemType: (index: number) => string;
length: number;
},
engagedIndicesOverride?: ConsecutiveNumbers
) => {
const dataLength = mock.length;
const engaged =
engagedIndicesOverride ??
new ConsecutiveNumbers(0, dataLength > 0 ? dataLength - 1 : -1);
manager.sync(mock.getStableId, mock.getItemType, engaged, dataLength);
return Array.from(manager.getRenderStack().keys()).sort(
(keyA, keyB) => Number(keyA) - Number(keyB)
);
};
// Helper to get keys specific to the items in a mock, after a sync
const getKeysForMockItems = (
manager: RenderStackManager,
mockData: {
data: { id: any }[];
getStableId: (index: number) => string;
length: number;
}
) => {
const stack = manager.getRenderStack();
const keys = [];
// Ensure we only try to get keys for items that exist in mockData
for (let i = 0; i < mockData.length; i++) {
const stableId = mockData.getStableId(i);
for (const [key, info] of stack.entries()) {
if (info.stableId === stableId) {
keys.push(key);
break;
}
}
}
return keys.sort((keyA, keyB) => Number(keyA) - Number(keyB));
};
const emptyMock = createMockData([]);
const mockDataA5 = createMockData([
{ id: "s1", itemType: "typeA" },
{ id: "s2", itemType: "typeA" },
{ id: "s3", itemType: "typeA" },
{ id: "s4", itemType: "typeA" },
{ id: "s5", itemType: "typeA" },
]);
const mockDataB3 = createMockData([
{ id: "s6", itemType: "typeA" },
{ id: "s7", itemType: "typeA" },
{ id: "s8", itemType: "typeA" },
]);
describe("RenderStackManager", () => {
it("should reuse keys from removed items when transitioning from mock1 to mock2", () => {
const renderStackManager = new RenderStackManager();
runSyncAndGetEntireKeyMapKeys(renderStackManager, mock1);
const oldRenderStackKeys = Array.from(
renderStackManager.getRenderStack().keys()
).sort((keyA, keyB) => Number(keyA) - Number(keyB));
runSyncAndGetEntireKeyMapKeys(renderStackManager, mock2);
const newRenderStackKeys = Array.from(
renderStackManager.getRenderStack().keys()
).sort((keyA, keyB) => Number(keyA) - Number(keyB));
expect(newRenderStackKeys).toEqual(oldRenderStackKeys);
});
it("should reuse keys changing item types when transitioning from mock3 to mock4", () => {
const renderStackManager = new RenderStackManager();
runSyncAndGetEntireKeyMapKeys(renderStackManager, mock3);
const oldRenderStackKeys = Array.from(
renderStackManager.getRenderStack().keys()
).sort((keyA, keyB) => Number(keyA) - Number(keyB));
runSyncAndGetEntireKeyMapKeys(renderStackManager, mock4);
const newRenderStackKeys = Array.from(
renderStackManager.getRenderStack().keys()
).sort((keyA, keyB) => Number(keyA) - Number(keyB));
expect(newRenderStackKeys).toEqual(oldRenderStackKeys);
});
it("should reuse keys changing item types when transitioning from mock4 to mock5", () => {
const renderStackManager = new RenderStackManager();
runSyncAndGetEntireKeyMapKeys(renderStackManager, mock4);
const oldRenderStackKeys = Array.from(
renderStackManager.getRenderStack().keys()
).sort((keyA, keyB) => Number(keyA) - Number(keyB));
runSyncAndGetEntireKeyMapKeys(renderStackManager, mock5);
const newRenderStackKeys = Array.from(
renderStackManager.getRenderStack().keys()
).sort((keyA, keyB) => Number(keyA) - Number(keyB));
expect(newRenderStackKeys).toEqual(oldRenderStackKeys);
});
it("should have all keys from mock1 when going from mock1 to mock5", () => {
const renderStackManager = new RenderStackManager();
runSyncAndGetEntireKeyMapKeys(renderStackManager, mock1);
const oldRenderStackKeys = Array.from(
renderStackManager.getRenderStack().keys()
).sort((keyA, keyB) => Number(keyA) - Number(keyB));
runSyncAndGetEntireKeyMapKeys(renderStackManager, mock5);
const newRenderStackKeys = Array.from(
renderStackManager.getRenderStack().keys()
).sort((keyA, keyB) => Number(keyA) - Number(keyB));
oldRenderStackKeys.forEach((key) => {
expect(newRenderStackKeys).toContain(key);
});
});
});
describe("RenderStackManager with disableRecycling = true", () => {
it("should assign new, non-recycled keys to new items when disableRecycling is true", () => {
const rsm = new RenderStackManager();
rsm.disableRecycling = true;
// Sync with A5 first
runSyncAndGetEntireKeyMapKeys(rsm, mockDataA5);
const keysA5 = getKeysForMockItems(rsm, mockDataA5);
expect(keysA5).toEqual(["0", "1", "2", "3", "4"]);
// Sync with B3
runSyncAndGetEntireKeyMapKeys(rsm, mockDataB3);
const keysB3 = getKeysForMockItems(rsm, mockDataB3);
expect(keysB3).toEqual(["5", "6", "7"]); // New keys for B3 items
// Ensure B3 keys don't overlap with A5 keys that might remain in keyMap
keysA5.forEach((keyA) => {
expect(keysB3).not.toContain(keyA);
});
// Check the final state of the entire keyMap
// After B3 sync, keys for A5 items at original indices 3,4 (stableIds "s4","s5")
// should be removed because 3 >= B3.length (3) and 4 >= B3.length (3). Keys for 0,1,2 from A5 remain.
const allKeysInMap = runSyncAndGetEntireKeyMapKeys(rsm, mockDataB3); // This re-syncs B3, ensuring state is for B3
expect(
allKeysInMap.sort((keyA, keyB) => Number(keyA) - Number(keyB))
).toEqual(["5", "6", "7"]);
});
it("should generate all new keys if starting with disableRecycling = true and items are removed then added", () => {
const rsm = new RenderStackManager();
rsm.disableRecycling = true;
runSyncAndGetEntireKeyMapKeys(rsm, mockDataA5); // Assigns keys "0" through "4"
runSyncAndGetEntireKeyMapKeys(rsm, emptyMock); // Sync with empty
expect(getKeysForMockItems(rsm, emptyMock)).toEqual([]);
runSyncAndGetEntireKeyMapKeys(rsm, mockDataB3); // Sync with new data
const keysForNewItems = getKeysForMockItems(rsm, mockDataB3);
expect(keysForNewItems).toEqual(["5", "6", "7"]);
});
});
describe("RenderStackManager with maxItemsInRecyclePool", () => {
it("should not recycle any keys when maxItemsInRecyclePool is 0", () => {
const rsm = new RenderStackManager(0); // maxItemsInRecyclePool = 0
runSyncAndGetEntireKeyMapKeys(rsm, mockDataA5);
runSyncAndGetEntireKeyMapKeys(rsm, emptyMock); // Sync with empty, dataLength = 0. All keys are cleaned up.
runSyncAndGetEntireKeyMapKeys(rsm, mockDataB3);
const keys2 = getKeysForMockItems(rsm, mockDataB3);
expect(keys2).toEqual(["5", "6", "7"]); // Expect new keys as pool was cleared by emptyMock sync
});
it("should effectively not recycle if intermediate sync has dataLength 0, regardless of maxPoolSize", () => {
const maxPoolSize = 2;
const rsm = new RenderStackManager(maxPoolSize);
runSyncAndGetEntireKeyMapKeys(rsm, mockDataA5);
runSyncAndGetEntireKeyMapKeys(rsm, emptyMock); // Sync with empty, dataLength = 0. All keys are cleaned up from pool and map.
const mockDataA3NewIds = createMockData([
{ id: "s10", itemType: "typeA" },
{ id: "s11", itemType: "typeA" },
{ id: "s12", itemType: "typeA" },
]);
runSyncAndGetEntireKeyMapKeys(rsm, mockDataA3NewIds);
const newKeys = getKeysForMockItems(rsm, mockDataA3NewIds);
// Because emptyMock sync (dataLength=0) clears all keys, these will be new.
expect(newKeys).toEqual(["5", "6", "7"]);
});
it("should not repeat index when going from mock6 to mock7", () => {
const rsm = new RenderStackManager();
rsm.disableRecycling = true;
runSyncAndGetEntireKeyMapKeys(rsm, mock6);
runSyncAndGetEntireKeyMapKeys(rsm, mock7);
const set = new Set<number>();
Array.from(rsm.getRenderStack().entries()).forEach(([key, info]) => {
expect(set.has(info.index)).toBe(false);
set.add(info.index);
});
});
});
describe("RenderStackManager edge cases", () => {
it("should handle initial sync with empty data and then add items", () => {
const rsm = new RenderStackManager();
runSyncAndGetEntireKeyMapKeys(rsm, emptyMock);
expect(getKeysForMockItems(rsm, emptyMock)).toEqual([]);
runSyncAndGetEntireKeyMapKeys(rsm, mockDataA5);
expect(getKeysForMockItems(rsm, mockDataA5)).toEqual([
"0",
"1",
"2",
"3",
"4",
]);
});
it("should generate new keys if all items removed (synced with empty) and then different items added", () => {
const rsm = new RenderStackManager(); // Default large pool size
runSyncAndGetEntireKeyMapKeys(rsm, mockDataA5);
runSyncAndGetEntireKeyMapKeys(rsm, emptyMock); // Sync with empty, dataLength = 0. All keys are cleaned up.
const mockDataA3NewIds = createMockData([
{ id: "s10", itemType: "typeA" },
{ id: "s11", itemType: "typeA" },
{ id: "s12", itemType: "typeA" },
]);
runSyncAndGetEntireKeyMapKeys(rsm, mockDataA3NewIds);
const newKeys = getKeysForMockItems(rsm, mockDataA3NewIds);
// Expect new keys as the emptyMock sync (dataLength=0) cleared the pool and map.
expect(newKeys).toEqual(["5", "6", "7"]);
});
it("should use new keys if types change completely and no compatible recycled keys exist (after empty sync)", () => {
const rsm = new RenderStackManager();
runSyncAndGetEntireKeyMapKeys(rsm, mockDataA5);
runSyncAndGetEntireKeyMapKeys(rsm, emptyMock); // Clear with empty sync
runSyncAndGetEntireKeyMapKeys(rsm, mockDataB3);
const keysTypeB = getKeysForMockItems(rsm, mockDataB3);
expect(keysTypeB).toEqual(["5", "6", "7"]); // Should be new keys after empty sync
const mockSingleTypeA = createMockData([{ id: "s20", itemType: "typeA" }]);
runSyncAndGetEntireKeyMapKeys(rsm, mockSingleTypeA);
const keyForS20 = getKeysForMockItems(rsm, mockSingleTypeA);
// After empty sync and B3 sync, A's pool is gone. Key counter is at 8.
expect(keyForS20).toEqual(["5"]);
});
it("should maintain keys if data and engaged indices do not change", () => {
const rsm = new RenderStackManager();
runSyncAndGetEntireKeyMapKeys(rsm, mockDataA5);
const keys1 = getKeysForMockItems(rsm, mockDataA5);
runSyncAndGetEntireKeyMapKeys(rsm, mockDataA5);
const keys2 = getKeysForMockItems(rsm, mockDataA5);
expect(keys2).toEqual(keys1);
});
it("should not delete keys from pool if they are not visible on index changes when going from mock6 to mock7", () => {
const rsm = new RenderStackManager();
runSyncAndGetEntireKeyMapKeys(rsm, mock6);
runSyncAndGetEntireKeyMapKeys(rsm, mock7, new ConsecutiveNumbers(3, 5));
const keys = getKeysForMockItems(rsm, mock7);
expect(keys).toEqual(["0", "1", "2", "3", "4", "5", "6", "7"]);
});
it("should not delete keys from pool if they are not visible on index changes when going from mock3 to mock8", () => {
const rsm = new RenderStackManager();
runSyncAndGetEntireKeyMapKeys(rsm, mock3, new ConsecutiveNumbers(0, 10));
runSyncAndGetEntireKeyMapKeys(rsm, mock8, new ConsecutiveNumbers(0, 13));
const keys = getKeysForMockItems(rsm, mock8);
expect(keys).toEqual([
"0",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"10",
"11",
"12",
"13",
]);
});
it("should delete keys from pool if they are not visible on index changes when going from mock6 to mock7 (disableRecycling = true)", () => {
const rsm = new RenderStackManager();
rsm.disableRecycling = true;
runSyncAndGetEntireKeyMapKeys(rsm, mock6);
runSyncAndGetEntireKeyMapKeys(rsm, mock7, new ConsecutiveNumbers(3, 5));
const keys = getKeysForMockItems(rsm, mock7);
expect(keys).toEqual(["0", "2", "3", "4", "5", "6", "8"]);
});
it("should not delete keys from pool if they are not visible on index changes when going from mock6 to mock7 (all engaged)", () => {
const rsm = new RenderStackManager();
runSyncAndGetEntireKeyMapKeys(rsm, mock6);
runSyncAndGetEntireKeyMapKeys(rsm, mock7);
const keys = getKeysForMockItems(rsm, mock7);
expect(keys).toEqual(["0", "1", "2", "3", "4", "5", "6", "7"]);
});
it("should delete keys from pool if they are not visible on index changes when going from mock6 to mock7 (all engaged,disableRecycling = true)", () => {
const rsm = new RenderStackManager();
rsm.disableRecycling = true;
runSyncAndGetEntireKeyMapKeys(rsm, mock6);
runSyncAndGetEntireKeyMapKeys(rsm, mock7);
const keys = getKeysForMockItems(rsm, mock7);
expect(keys).toEqual(["0", "2", "3", "4", "5", "6", "7", "8"]);
});
it("should correctly handle partial replacement of items, reusing keys for stable items and recycling for replaced ones", () => {
const rsm = new RenderStackManager();
const initialMock = createMockData([
{ id: "s1", itemType: "typeA" },
{ id: "s2", itemType: "typeA" },
{ id: "s3", itemType: "typeA" },
{ id: "s4", itemType: "typeA" },
]);
runSyncAndGetEntireKeyMapKeys(rsm, initialMock);
const initialKeyMap = new Map<string, string>();
// Populate initialKeyMap correctly using getKeysForMockItems and stable IDs
initialMock.data.forEach((itemData, index) => {
// Get the keys for the initialMock items AFTER the sync.
const currentKeysForInitialMock = getKeysForMockItems(rsm, initialMock);
const key = currentKeysForInitialMock[index]; // Assumes keys are in order of data
if (key !== undefined) {
// Ensure key exists before setting
initialKeyMap.set(itemData.id.toString(), key);
}
});
const keyForS1 = initialKeyMap.get("s1")!;
const keyForS2 = initialKeyMap.get("s2")!;
const keyForS3 = initialKeyMap.get("s3")!;
const keyForS4 = initialKeyMap.get("s4")!;
const partiallyReplacedMock = createMockData([
{ id: "s1", itemType: "typeA" },
{ id: "s5", itemType: "typeA" },
{ id: "s6", itemType: "typeA" },
{ id: "s4", itemType: "typeA" },
]);
runSyncAndGetEntireKeyMapKeys(rsm, partiallyReplacedMock);
const finalKeyMap = new Map<string, string>();
partiallyReplacedMock.data.forEach((itemData, index) => {
// Get keys for partiallyReplacedMock items AFTER the sync.
const currentKeysForPartialMock = getKeysForMockItems(
rsm,
partiallyReplacedMock
);
const key = currentKeysForPartialMock[index]; // Assumes keys are in order
if (key !== undefined) {
// Ensure key exists
finalKeyMap.set(itemData.id.toString(), key);
}
});
expect(finalKeyMap.get("s1")).toBe(keyForS1);
expect(finalKeyMap.get("s4")).toBe(keyForS4);
expect([finalKeyMap.get("s5"), finalKeyMap.get("s6")]).toEqual(
expect.arrayContaining([keyForS2, keyForS3])
);
expect(finalKeyMap.get("s5")).not.toBe(finalKeyMap.get("s6"));
const finalKeysForCurrentItems = getKeysForMockItems(
rsm,
partiallyReplacedMock
);
expect(finalKeysForCurrentItems).toEqual(["0", "1", "2", "3"]);
});
});