firebase messaging.sendToDevice()をsinonで置き換える
https://firebase.google.com/docs/cloud-messaging/send-message?hl=ja#send-to-individual-devices
注: 1 つのリクエストでメッセージを送信できる宛先デバイスの最大数は 1,000 台です。配列に 1,000 を超える登録トークンを指定すると、そのリクエストは messaging/invalid-recipient エラーで失敗します。
ということなので分割して送信することにしました。 分割するロジックはfor文で回す感じにしたので、無限ループが怖いので テストコードで確認しました。
他のtest spyみたいなのは使ったことがありますが、 sinonは初めてでしたが、公式のサンプルで使われていたので。
https://firebase.google.cn/docs/functions/unit-testing?hl=ja
import * as admin from 'firebase-admin'; import { messaging } from 'firebase-admin'; import MessagingPayload = messaging.MessagingPayload; import MessagingOptions = messaging.MessagingOptions; import MessagingDevicesResponse = messaging.MessagingDevicesResponse; /** * // https://firebase.google.com/docs/cloud-messaging/send-message?hl=ja#send-to-individual-devices * divisionUnit=1000 */ export async function batchSendToDevice( fcmTokens: string[], divisionUnit: number, message: MessagingPayload, options: MessagingOptions) : Promise<MessagingDevicesResponse[]> { const promises = []; for (let i = 0; i < fcmTokens.length; i += divisionUnit) { const dividedTokens = fcmTokens.slice(i, i + divisionUnit); promises.push(admin.messaging().sendToDevice(dividedTokens, message, options)); } return await Promise.all(promises); }
テストコード
import * as admin from 'firebase-admin'; import { messaging } from 'firebase-admin'; import MessagingDevicesResponse = messaging.MessagingDevicesResponse; import * as sinon from 'sinon'; import { batchSendToDevice } from './batch-send-to-device'; admin.initializeApp(); describe("batchSendToDevice", () => { it("Split logic works fine", async () => { const sandbox = sinon.createSandbox({}); const messaging = admin.messaging(); sandbox.replace(messaging, 'sendToDevice', (registrationToken, payload, options) => { const response: MessagingDevicesResponse = { canonicalRegistrationTokenCount: 1, failureCount: 0, multicastId: 1, results: [], successCount: 1 }; if (!Array.isArray(registrationToken)) { response.multicastId = Number(registrationToken); return new Promise((result, reject) => { return result(response); }); } registrationToken.forEach((e) => { response.results.push({ messageId: e }); return response; }); return new Promise((result, reject) => { return result(response); }); }); const tokens = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11']; const ret = await batchSendToDevice(tokens, 5, {}, {}); console.log(JSON.stringify(ret, null, 2)); }); });
完全なサンプル https://github.com/na8esin/firebase-practice/tree/master/functions/src