diff --git a/src/lib/__tests__/sendMessage.js b/src/lib/__tests__/sendMessage.js index 0e505e56..6007702b 100644 --- a/src/lib/__tests__/sendMessage.js +++ b/src/lib/__tests__/sendMessage.js @@ -6,7 +6,7 @@ import rollbar from 'src/lib/rollbar'; import sendMessage from '../sendMessage'; beforeEach(() => { - fetch.mockClear(); + fetch.mockReset(); rollbar.error.mockClear(); }); @@ -29,8 +29,12 @@ it('send message using LINE Notify', () => { `); }); -it('send message using multicast api', () => { - sendMessage.multicast( +it('send message using multicast api', async () => { + fetch.mockImplementation(() => + Promise.resolve({ json: () => Promise.resolve({ status: 200 }) }) + ); + + await sendMessage.multicast( ['userId1', 'userId2', 'userId3'], [{ type: 'text', text: 'message' }] ); @@ -49,6 +53,30 @@ it('send message using multicast api', () => { ], ] `); + + // Test batching + fetch.mockClear(); + await sendMessage.multicast( + Array.from(Array(501)).map((_, id) => `user${id}`), + [{ type: 'text', text: 'message' }] + ); + + expect(fetch.mock.calls).toHaveLength(2); + + // The snapshot of the "second batch", which should only contain user500 + expect(fetch.mock.calls[1]).toMatchInlineSnapshot(` + Array [ + "https://api.line.me/v2/bot/message/multicast", + Object { + "body": "{\\"to\\":[\\"user500\\"],\\"messages\\":[{\\"type\\":\\"text\\",\\"text\\":\\"message\\"}]}", + "headers": Object { + "Authorization": "Bearer ", + "Content-Type": "application/json", + }, + "method": "POST", + }, + ] + `); }); it('send message using push api', () => { diff --git a/src/lib/sendMessage.js b/src/lib/sendMessage.js index b2a4a9bc..ce7b60be 100644 --- a/src/lib/sendMessage.js +++ b/src/lib/sendMessage.js @@ -10,16 +10,40 @@ const notify = async (token, message) => { lineNotify(token, { message: message }); }; +/** + * Split large array into list of batches, with max size being batchSize for each batch + * @param {Array<*>} array + * @param {number} batchSize + * @returns {Array>} + */ +function batch(array, batchSize) { + return array.reduce( + (batches, item) => { + if (batches[batches.length - 1].length >= batchSize) { + batches.push([]); + } + batches[batches.length - 1].push(item); + return batches; + }, + [[]] + ); +} + /** * https://developers.line.biz/en/reference/messaging-api/#send-multicast-message * @param {string[]} userIds * @param {object[]} messages - Array of line message objects, max size:5 */ const multicast = async (userIds, messages) => { - lineClient.post('/message/multicast', { - to: userIds, - messages: messages, - }); + for (const userIdBatch of batch( + userIds, + 500 /* Multicast can send to 500 ppl in max each time */ + )) { + await lineClient.post('/message/multicast', { + to: userIdBatch, + messages: messages, + }); + } }; /** @@ -27,12 +51,11 @@ const multicast = async (userIds, messages) => { * @param {string} userId * @param {object[]} messages - Array of line message objects, max size:5 */ -const push = async (userId, messages) => { +const push = (userId, messages) => lineClient.post('/message/push', { to: userId, messages: messages, }); -}; export default { notify,