From 701183f63487706433ce0f2e3034700b41aae3ef Mon Sep 17 00:00:00 2001 From: Anton Arnautov Date: Thu, 19 Sep 2024 15:33:55 +0200 Subject: [PATCH 1/3] Enable midpoint matching in findIndexInSortedArray, use it instead of binarySearchByDateEqualOrNearestGreater --- src/utils.ts | 39 ++++------------- test/unit/utils.js | 20 --------- test/unit/utils.test.ts | 92 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 91 insertions(+), 60 deletions(-) diff --git a/src/utils.ts b/src/utils.ts index ba63af8b6..3e6a2ebe1 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -353,7 +353,7 @@ export const findIndexInSortedArray = ({ const comparableMiddle = selectValueToCompare(sortedArray[middle]); - // if (comparableNeedle === comparableMiddle) return middle; + if (comparableNeedle === comparableMiddle) return middle; if ( (sortDirection === 'ascending' && comparableNeedle < comparableMiddle) || @@ -499,36 +499,6 @@ type MessagePaginationUpdatedParams({ parentSet, requestedPageSize, @@ -580,7 +550,12 @@ const messagePaginationCreatedAtAround = ({ + needle: { created_at: createdAtAroundDate }, + sortedArray: returnedPage.map(formatMessage), + sortDirection: 'ascending', + selectValueToCompare: (message) => message.created_at.getTime(), + }); if (midPointByCreationDate !== -1) { hasPrev = midPointByCount <= midPointByCreationDate; diff --git a/test/unit/utils.js b/test/unit/utils.js index 1a1da8ec0..6a13a7d7b 100644 --- a/test/unit/utils.js +++ b/test/unit/utils.js @@ -2690,23 +2690,3 @@ describe('messageSetPagination', () => { }); }); }); - -describe('', () => { - const messages = [ - { created_at: '2024-08-05T08:55:00.199808Z', id: '0' }, - { created_at: '2024-08-05T08:55:01.199808Z', id: '1' }, - { created_at: '2024-08-05T08:55:02.199808Z', id: '2' }, - { created_at: '2024-08-05T08:55:03.199808Z', id: '3' }, - { created_at: '2024-08-05T08:55:04.199808Z', id: '4' }, - { created_at: '2024-08-05T08:55:05.199808Z', id: '5' }, - { created_at: '2024-08-05T08:55:06.199808Z', id: '6' }, - { created_at: '2024-08-05T08:55:07.199808Z', id: '7' }, - { created_at: '2024-08-05T08:55:08.199808Z', id: '8' }, - ]; - it('finds the nearest newer item', () => { - expect(binarySearchByDateEqualOrNearestGreater(messages, new Date('2024-08-05T08:55:02.299808Z'))).to.eql(3); - }); - it('finds the nearest matching item', () => { - expect(binarySearchByDateEqualOrNearestGreater(messages, new Date('2024-08-05T08:55:07.199808Z'))).to.eql(7); - }); -}); diff --git a/test/unit/utils.test.ts b/test/unit/utils.test.ts index 04f107804..df12464e0 100644 --- a/test/unit/utils.test.ts +++ b/test/unit/utils.test.ts @@ -3,12 +3,12 @@ import { v4 as uuidv4 } from 'uuid'; import { generateMsg } from './test-utils/generateMessage'; -import { addToMessageList, formatMessage } from '../../src/utils'; +import { addToMessageList, findIndexInSortedArray, formatMessage } from '../../src/utils'; import type { FormatMessageResponse, MessageResponse } from '../../src'; describe('addToMessageList', () => { - const timestamp = new Date('2024-09-18T15:30:00.000Z').getTime(); + const timestamp = new Date('2024-01-01T00:00:00.000Z').getTime(); // messages with each created_at 10 seconds apart let messagesBefore: FormatMessageResponse[]; @@ -93,15 +93,91 @@ describe('addToMessageList', () => { }); it("updates an existing message that wasn't filtered due to changed timestamp (timestampChanged)", () => { - const newMessage = getNewFormattedMessage({ timeOffset: 30 * 1000, id: messagesBefore[4].id }); + const newMessage = getNewFormattedMessage({ timeOffset: 30 * 1000, id: messagesBefore[3].id }); - expect(messagesBefore[4].id).to.equal(newMessage.id); - expect(messagesBefore[4].text).to.not.equal(newMessage.text); - expect(messagesBefore[4]).to.not.equal(newMessage); + expect(messagesBefore[3].id).to.equal(newMessage.id); + expect(messagesBefore[3].text).to.not.equal(newMessage.text); + expect(messagesBefore[3]).to.not.equal(newMessage); - const messagesAfter = addToMessageList(messagesBefore, newMessage, false, 'created_at', false); + const messagesAfter = addToMessageList(messagesBefore, newMessage, false); expect(messagesAfter).to.have.length(5); - expect(messagesAfter[4]).to.equal(newMessage); + expect(messagesAfter[3]).to.equal(newMessage); + }); +}); + +describe('findIndexInSortedArray', () => { + const timestamp = new Date('2024-01-01T00:00:00.000Z').getTime(); + + const generateMessages = ({ count = 10, sort = 'desc' }: { count?: number; sort?: 'asc' | 'desc' } = {}) => { + const messages = Array.from({ length: count }, (_, index) => + generateMsg({ created_at: new Date(timestamp + index * 10 * 1000).toISOString() }), + ); + + if (sort === 'desc') { + messages.reverse(); + } + + return messages as MessageResponse[]; + }; + + describe('ascending order', () => { + const messages = generateMessages({ sort: 'asc' }).map(formatMessage); + + it('finds index of the message with closest matching created_at', () => { + const newMessage = formatMessage(generateMsg({ created_at: new Date(timestamp + 22 * 1000) }) as MessageResponse); + + const index = findIndexInSortedArray({ + needle: newMessage, + sortedArray: messages, + sortDirection: 'ascending', + selectValueToCompare: (v) => v.created_at.getTime(), + }); + + expect(index).to.equal(3); + }); + + it('finds exact index', () => { + const newMessage = formatMessage(generateMsg({ created_at: new Date(timestamp + 20 * 1000) }) as MessageResponse); + + const index = findIndexInSortedArray({ + needle: newMessage, + sortedArray: messages, + sortDirection: 'ascending', + selectValueToCompare: (v) => v.created_at.getTime(), + }); + + expect(index).to.equal(2); + }); + }); + + describe('descending order', () => { + const messages = generateMessages({ sort: 'desc' }).map(formatMessage); + + it('finds index of the message with closest matching created_at', () => { + const newMessage = formatMessage(generateMsg({ created_at: new Date(timestamp + 22 * 1000) }) as MessageResponse); + + const index = findIndexInSortedArray({ + needle: newMessage, + sortedArray: messages, + sortDirection: 'descending', + selectValueToCompare: (v) => v.created_at.getTime(), + }); + + expect(index).to.equal(7); + }); + + it('finds exact index', () => { + const newMessage = formatMessage(generateMsg({ created_at: new Date(timestamp + 10 * 1000) }) as MessageResponse); + + const index = findIndexInSortedArray({ + needle: newMessage, + sortedArray: messages, + sortDirection: 'descending', + selectValueToCompare: (v) => v.created_at.getTime(), + }); + + expect(index).to.equal(8); + }); }); }); From 544753a37b9613bc9ee29328261489d717c11043 Mon Sep 17 00:00:00 2001 From: Anton Arnautov Date: Thu, 19 Sep 2024 15:34:40 +0200 Subject: [PATCH 2/3] Adjust related tests --- test/unit/channel.js | 6 ++- test/unit/channel_state.js | 102 ++++++++++++++++++++++++++++--------- 2 files changed, 83 insertions(+), 25 deletions(-) diff --git a/test/unit/channel.js b/test/unit/channel.js index b72ec4b61..79cffff2e 100644 --- a/test/unit/channel.js +++ b/test/unit/channel.js @@ -1275,9 +1275,13 @@ describe('Channel.query', async () => { it('should update pagination for queried message set to prevent more pagination', async () => { const client = await getClientWithUser(); const channel = client.channel('messaging', uuidv4()); + const timestamp = new Date('2024-01-01T00:00:00.000Z').getTime(); + const mockedChannelQueryResponse = { ...mockChannelQueryResponse, - messages: Array.from({ length: DEFAULT_QUERY_CHANNEL_MESSAGE_LIST_PAGE_SIZE - 1 }, generateMsg), + messages: Array.from({ length: DEFAULT_QUERY_CHANNEL_MESSAGE_LIST_PAGE_SIZE - 1 }, (_, index) => + generateMsg({ created_at: new Date(timestamp + index * 1000).toISOString() }), + ), }; const mock = sinon.mock(client); mock.expects('post').returns(Promise.resolve(mockedChannelQueryResponse)); diff --git a/test/unit/channel_state.js b/test/unit/channel_state.js index 7e66e2a69..945d9b54e 100644 --- a/test/unit/channel_state.js +++ b/test/unit/channel_state.js @@ -110,8 +110,8 @@ describe('ChannelState addMessagesSorted', function () { expect(state.messages).to.have.length(10); state.addMessagesSorted([generateMsg({ id: 'id', date: `2020-01-01T00:00:00.007Z` })]); expect(state.messages).to.have.length(11); - expect(state.messages[7].id).to.be.equal('7'); - expect(state.messages[8].id).to.be.equal('id'); + expect(state.messages[7].id).to.be.equal('id'); + expect(state.messages[8].id).to.be.equal('7'); }); it('add lots of messages in order', async function () { @@ -208,8 +208,22 @@ describe('ChannelState addMessagesSorted', function () { it('should add messages to new message set', () => { const state = new ChannelState(); - state.addMessagesSorted([generateMsg({ id: '12' }), generateMsg({ id: '13' }), generateMsg({ id: '14' })]); - state.addMessagesSorted([generateMsg({ id: '0' }), generateMsg({ id: '1' })], false, false, true, 'new'); + + state.addMessagesSorted([ + generateMsg({ id: '12', created_at: '2020-01-01T00:00:00.001Z' }), + generateMsg({ id: '13', created_at: '2020-01-01T00:00:00.002Z' }), + generateMsg({ id: '14', created_at: '2020-01-01T00:00:00.003Z' }), + ]); + state.addMessagesSorted( + [ + generateMsg({ id: '0', created_at: '2020-01-01T00:00:00.004Z' }), + generateMsg({ id: '1', created_at: '2020-01-01T00:00:00.005Z' }), + ], + false, + false, + true, + 'new', + ); expect(state.messages.length).to.be.equal(3); expect(state.messages[0].id).to.be.equal('12'); @@ -223,7 +237,11 @@ describe('ChannelState addMessagesSorted', function () { it('should add messages to current message set', () => { const state = new ChannelState(); state.addMessagesSorted( - [generateMsg({ id: '12' }), generateMsg({ id: '13' }), generateMsg({ id: '14' })], + [ + generateMsg({ id: '12', created_at: '2020-01-01T00:00:00.001Z' }), + generateMsg({ id: '13', created_at: '2020-01-01T00:00:00.002Z' }), + generateMsg({ id: '14', created_at: '2020-01-01T00:00:00.003Z' }), + ], false, false, true, @@ -239,7 +257,11 @@ describe('ChannelState addMessagesSorted', function () { it('should add messages to latest message set', () => { const state = new ChannelState(); state.addMessagesSorted( - [generateMsg({ id: '12' }), generateMsg({ id: '13' }), generateMsg({ id: '14' })], + [ + generateMsg({ id: '12', created_at: '2020-01-01T00:00:00.001Z' }), + generateMsg({ id: '13', created_at: '2020-01-01T00:00:00.002Z' }), + generateMsg({ id: '14', created_at: '2020-01-01T00:00:00.003Z' }), + ], false, false, true, @@ -258,17 +280,37 @@ describe('ChannelState addMessagesSorted', function () { it(`should add messages to latest message set when it's not currently active`, () => { const state = new ChannelState(); + state.addMessagesSorted( - [generateMsg({ id: '12' }), generateMsg({ id: '13' }), generateMsg({ id: '14' })], + [ + generateMsg({ id: '12', created_at: '2020-01-01T00:00:00.001Z' }), + generateMsg({ id: '13', created_at: '2020-01-01T00:00:00.002Z' }), + generateMsg({ id: '14', created_at: '2020-01-01T00:00:00.003Z' }), + ], false, false, true, 'latest', ); - state.addMessagesSorted([generateMsg({ id: '0' }), generateMsg({ id: '1' })], false, false, true, 'new'); + state.addMessagesSorted( + [ + generateMsg({ id: '0', created_at: '2020-01-01T00:00:00.004Z' }), + generateMsg({ id: '1', created_at: '2020-01-01T00:00:00.005Z' }), + ], + false, + false, + true, + 'new', + ); state.messageSets[0].isCurrent = false; state.messageSets[1].isCurrent = true; - state.addMessagesSorted([generateMsg({ id: '15' })], false, false, true, 'latest'); + state.addMessagesSorted( + [generateMsg({ id: '15', created_at: '2020-01-01T00:00:00.006Z' })], + false, + false, + true, + 'latest', + ); expect(state.latestMessages.length).to.be.equal(4); expect(state.latestMessages[3].id).to.be.equal('15'); @@ -684,10 +726,10 @@ describe('deleteUserMessages', () => { const user1 = generateUser(); const user2 = generateUser(); - const m1u1 = generateMsg({ user: user1 }); - const m2u1 = generateMsg({ user: user1 }); - const m1u2 = generateMsg({ user: user2 }); - const m2u2 = generateMsg({ user: user2 }); + const m1u1 = generateMsg({ user: user1, created_at: '2020-01-01T00:00:00.001Z' }); + const m2u1 = generateMsg({ user: user1, created_at: '2020-01-01T00:00:00.002Z' }); + const m1u2 = generateMsg({ user: user2, created_at: '2020-01-01T00:00:00.003Z' }); + const m2u2 = generateMsg({ user: user2, created_at: '2020-01-01T00:00:00.004Z' }); state.addMessagesSorted([m1u1, m2u1, m1u2, m2u2]); @@ -719,10 +761,10 @@ describe('deleteUserMessages', () => { const user1 = generateUser(); const user2 = generateUser(); - const m1u1 = generateMsg({ user: user1 }); - const m2u1 = generateMsg({ user: user1 }); - const m1u2 = generateMsg({ user: user2 }); - const m2u2 = generateMsg({ user: user2 }); + const m1u1 = generateMsg({ user: user1, created_at: '2020-01-01T00:00:00.001Z' }); + const m2u1 = generateMsg({ user: user1, created_at: '2020-01-01T00:00:00.002Z' }); + const m1u2 = generateMsg({ user: user2, created_at: '2020-01-01T00:00:00.003Z' }); + const m2u2 = generateMsg({ user: user2, created_at: '2020-01-01T00:00:00.004Z' }); state.addMessagesSorted([m1u1, m2u1, m1u2, m2u2]); expect(state.messages).to.have.length(4); @@ -755,10 +797,10 @@ describe('updateUserMessages', () => { let user1 = generateUser(); const user2 = generateUser(); - const m1u1 = generateMsg({ user: user1 }); - const m2u1 = generateMsg({ user: user1 }); - const m1u2 = generateMsg({ user: user2 }); - const m2u2 = generateMsg({ user: user2 }); + const m1u1 = generateMsg({ user: user1, created_at: '2020-01-01T00:00:00.001Z' }); + const m2u1 = generateMsg({ user: user1, created_at: '2020-01-01T00:00:00.002Z' }); + const m1u2 = generateMsg({ user: user2, created_at: '2020-01-01T00:00:00.003Z' }); + const m2u2 = generateMsg({ user: user2, created_at: '2020-01-01T00:00:00.004Z' }); state.addMessagesSorted([m1u1, m2u1, m1u2, m2u2]); @@ -785,7 +827,11 @@ describe('updateUserMessages', () => { describe('latestMessages', () => { it('should return latest messages - if they are the current message set', () => { const state = new ChannelState(); - const messages = [generateMsg({ id: '1' }), generateMsg({ id: '2' }), generateMsg({ id: '3' })]; + const messages = [ + generateMsg({ id: '1', created_at: '2020-01-01T00:00:00.001Z' }), + generateMsg({ id: '2', created_at: '2020-01-01T00:00:00.002Z' }), + generateMsg({ id: '3', created_at: '2020-01-01T00:00:00.003Z' }), + ]; state.addMessagesSorted(messages); expect(state.latestMessages.length).to.be.equal(messages.length); @@ -796,7 +842,11 @@ describe('latestMessages', () => { it('should return latest messages - if they are not the current message set', () => { const state = new ChannelState(); - const latestMessages = [generateMsg({ id: '1' }), generateMsg({ id: '2' }), generateMsg({ id: '3' })]; + const latestMessages = [ + generateMsg({ id: '1', created_at: '2020-01-01T00:00:00.001Z' }), + generateMsg({ id: '2', created_at: '2020-01-01T00:00:00.002Z' }), + generateMsg({ id: '3', created_at: '2020-01-01T00:00:00.003Z' }), + ]; state.addMessagesSorted(latestMessages); const newMessages = [generateMsg({ id: '0' })]; state.addMessagesSorted(newMessages, false, true, true, 'new'); @@ -811,7 +861,11 @@ describe('latestMessages', () => { it('should return latest messages - if they are not the current message set and new messages received', () => { const state = new ChannelState(); - const latestMessages = [generateMsg({ id: '1' }), generateMsg({ id: '2' }), generateMsg({ id: '3' })]; + const latestMessages = [ + generateMsg({ id: '1', created_at: '2020-01-01T00:00:00.001Z' }), + generateMsg({ id: '2', created_at: '2020-01-01T00:00:00.002Z' }), + generateMsg({ id: '3', created_at: '2020-01-01T00:00:00.003Z' }), + ]; state.addMessagesSorted(latestMessages); const newMessages = [generateMsg({ id: '0' })]; state.addMessagesSorted(newMessages, false, true, true, 'new'); From d0098827b457626ea9d35a04c97271d3b00bff8d Mon Sep 17 00:00:00 2001 From: martincupela Date: Mon, 21 Oct 2024 15:48:59 +0200 Subject: [PATCH 3/3] fix: hide search by midpoint behind a flag --- src/utils.ts | 8 ++- test/unit/channel_state.js | 40 +++++++++---- test/unit/utils.test.ts | 119 ++++++++++++++++++++++++++----------- 3 files changed, 119 insertions(+), 48 deletions(-) diff --git a/src/utils.ts b/src/utils.ts index 3e6a2ebe1..89f28e20b 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -310,12 +310,18 @@ export function formatMessage({ needle, + returnOnMidMatch, sortedArray, selectValueToCompare = (e) => e, sortDirection = 'ascending', }: { needle: T; sortedArray: readonly T[]; + /** + * Returns the index of the midpoint if it matches the target value. + * Should be enabled only if the searched array cannot contain duplicates. + */ + returnOnMidMatch?: boolean; /** * In array of objects (like messages), pick a specific * property to compare needle value to. @@ -353,7 +359,7 @@ export const findIndexInSortedArray = ({ const comparableMiddle = selectValueToCompare(sortedArray[middle]); - if (comparableNeedle === comparableMiddle) return middle; + if (returnOnMidMatch && comparableNeedle === comparableMiddle) return middle; if ( (sortDirection === 'ascending' && comparableNeedle < comparableMiddle) || diff --git a/test/unit/channel_state.js b/test/unit/channel_state.js index 945d9b54e..6b741f105 100644 --- a/test/unit/channel_state.js +++ b/test/unit/channel_state.js @@ -97,21 +97,39 @@ describe('ChannelState addMessagesSorted', function () { it('add a message with same created_at', async function () { const state = new ChannelState(); - - for (let i = 0; i < 10; i++) { - state.addMessagesSorted([generateMsg({ id: `${i}`, date: `2020-01-01T00:00:00.00${i}Z` })]); + const pairCount = 10; + const msgCount = pairCount * 2; + + for (let i = 0; i < msgCount; i += 2) { + state.addMessagesSorted([ + generateMsg({ id: `${i}`, date: `2020-01-01T00:00:00.0${i.toString().padStart(2, '0')}Z` }), + generateMsg({ id: `${i + 1}`, date: `2020-01-01T00:00:00.0${i.toString().padStart(2, '0')}Z` }), + ]); } - for (let i = 10; i < state.messages.length - 1; i++) { - for (let j = i + 1; i < state.messages.length - 1; j++) - expect(state.messages[i].created_at.getTime()).to.be.lessThan(state.messages[j].created_at.getTime()); + for (let i = 0; i < msgCount; i += 2) { + expect(state.messages[i].created_at.getTime()).to.be.eq(state.messages[i + 1].created_at.getTime()); + if (i + 2 < msgCount) { + expect(state.messages[i].created_at.getTime()).to.be.lessThan( + state.messages[i + 2].created_at.getTime(), + ); + } } - expect(state.messages).to.have.length(10); - state.addMessagesSorted([generateMsg({ id: 'id', date: `2020-01-01T00:00:00.007Z` })]); - expect(state.messages).to.have.length(11); - expect(state.messages[7].id).to.be.equal('id'); - expect(state.messages[8].id).to.be.equal('7'); + expect(state.messages).to.have.length(msgCount); + state.addMessagesSorted([generateMsg({ id: '1stAdded', date: `2020-01-01T00:00:00.014Z` })]); + + expect(state.messages).to.have.length(msgCount + 1); + expect(state.messages[14].id).to.be.equal('14'); + expect(state.messages[15].id).to.be.equal('15'); + expect(state.messages[16].id).to.be.equal('1stAdded'); + state.addMessagesSorted([generateMsg({ id: '2ndAdded', date: `2020-01-01T00:00:00.014Z` })]); + + expect(state.messages).to.have.length(msgCount + 2); + expect(state.messages[14].id).to.be.equal('14'); + expect(state.messages[15].id).to.be.equal('15'); + expect(state.messages[16].id).to.be.equal('1stAdded'); + expect(state.messages[17].id).to.be.equal('2ndAdded'); }); it('add lots of messages in order', async function () { diff --git a/test/unit/utils.test.ts b/test/unit/utils.test.ts index df12464e0..7e95c1954 100644 --- a/test/unit/utils.test.ts +++ b/test/unit/utils.test.ts @@ -125,29 +125,53 @@ describe('findIndexInSortedArray', () => { const messages = generateMessages({ sort: 'asc' }).map(formatMessage); it('finds index of the message with closest matching created_at', () => { - const newMessage = formatMessage(generateMsg({ created_at: new Date(timestamp + 22 * 1000) }) as MessageResponse); - - const index = findIndexInSortedArray({ - needle: newMessage, - sortedArray: messages, - sortDirection: 'ascending', - selectValueToCompare: (v) => v.created_at.getTime(), + [ + { + newMessage: formatMessage(generateMsg({ created_at: new Date(timestamp + 22 * 1000) }) as MessageResponse), + returnOnMidMatch: true, + }, + { + newMessage: formatMessage(generateMsg({ created_at: new Date(timestamp + 22 * 1000) }) as MessageResponse), + returnOnMidMatch: false, + }, + ].forEach(({ newMessage, returnOnMidMatch }) => { + const index = findIndexInSortedArray({ + needle: newMessage, + returnOnMidMatch, + sortedArray: messages, + sortDirection: 'ascending', + selectValueToCompare: (v) => v.created_at.getTime(), + }); + + expect(index).to.equal(3); }); - - expect(index).to.equal(3); }); it('finds exact index', () => { - const newMessage = formatMessage(generateMsg({ created_at: new Date(timestamp + 20 * 1000) }) as MessageResponse); - - const index = findIndexInSortedArray({ - needle: newMessage, - sortedArray: messages, - sortDirection: 'ascending', - selectValueToCompare: (v) => v.created_at.getTime(), + [ + { + newMessage: formatMessage(generateMsg({ created_at: new Date(timestamp + 20 * 1000) }) as MessageResponse), + returnOnMidMatch: true, + }, + { + newMessage: formatMessage(generateMsg({ created_at: new Date(timestamp + 20 * 1000) }) as MessageResponse), + returnOnMidMatch: false, + }, + ].forEach(({ newMessage, returnOnMidMatch }) => { + const index = findIndexInSortedArray({ + needle: newMessage, + returnOnMidMatch, + sortedArray: messages, + sortDirection: 'ascending', + selectValueToCompare: (v) => v.created_at.getTime(), + }); + + if (returnOnMidMatch) { + expect(index).to.equal(2); + } else { + expect(index).to.equal(3); + } }); - - expect(index).to.equal(2); }); }); @@ -155,29 +179,52 @@ describe('findIndexInSortedArray', () => { const messages = generateMessages({ sort: 'desc' }).map(formatMessage); it('finds index of the message with closest matching created_at', () => { - const newMessage = formatMessage(generateMsg({ created_at: new Date(timestamp + 22 * 1000) }) as MessageResponse); - - const index = findIndexInSortedArray({ - needle: newMessage, - sortedArray: messages, - sortDirection: 'descending', - selectValueToCompare: (v) => v.created_at.getTime(), + [ + { + newMessage: formatMessage(generateMsg({ created_at: new Date(timestamp + 22 * 1000) }) as MessageResponse), + returnOnMidMatch: true, + }, + { + newMessage: formatMessage(generateMsg({ created_at: new Date(timestamp + 22 * 1000) }) as MessageResponse), + returnOnMidMatch: false, + }, + ].forEach(({ newMessage, returnOnMidMatch }) => { + const index = findIndexInSortedArray({ + needle: newMessage, + returnOnMidMatch, + sortedArray: messages, + sortDirection: 'descending', + selectValueToCompare: (v) => v.created_at.getTime(), + }); + + expect(index).to.equal(7); }); - - expect(index).to.equal(7); }); it('finds exact index', () => { - const newMessage = formatMessage(generateMsg({ created_at: new Date(timestamp + 10 * 1000) }) as MessageResponse); - - const index = findIndexInSortedArray({ - needle: newMessage, - sortedArray: messages, - sortDirection: 'descending', - selectValueToCompare: (v) => v.created_at.getTime(), + [ + { + newMessage: formatMessage(generateMsg({ created_at: new Date(timestamp + 10 * 1000) }) as MessageResponse), + returnOnMidMatch: true, + }, + { + newMessage: formatMessage(generateMsg({ created_at: new Date(timestamp + 10 * 1000) }) as MessageResponse), + returnOnMidMatch: false, + }, + ].forEach(({ newMessage, returnOnMidMatch }) => { + const index = findIndexInSortedArray({ + needle: newMessage, + returnOnMidMatch, + sortedArray: messages, + sortDirection: 'descending', + selectValueToCompare: (v) => v.created_at.getTime(), + }); + if (returnOnMidMatch) { + expect(index).to.equal(8); + } else { + expect(index).to.equal(9); + } }); - - expect(index).to.equal(8); }); }); });