sendPushNotificationsAsync never returns

I am running the basic example for the Node.js expo-server-sdk’s push notifications and the code that runs

let ticketChunk = await expo.sendPushNotificationsAsync(chunk);

never returns.

I think traced it down into the expo-server-sdk source code and this is the line that runs but never returns:

            console.log("testing start")
            let response = yield this._limitConcurrentRequests(() => node_fetch_1.default(url, {
                method: options.httpMethod,
                body: requestBody,
                headers: requestHeaders,
                agent: this._httpAgent,
            }));
            console.log("testing end")

I see the “testing start” in my console but never see the “testing end”

Here is the full code that calls it (comments removed for brevity):

const { Expo } = require('expo-server-sdk')

function sendNotification() {
    let expo = new Expo();
    let tokens = ['ExponentPushToken[____REDACTED_TOKEN____]']
    let messages = [];
    for (let pushToken of tokens) {
        if (!Expo.isExpoPushToken(pushToken)) {
            console.error(`Push token ${pushToken} is not a valid Expo push token`);
            continue;
        }
        messages.push({
            to: pushToken,
            sound: 'default',
            body: 'This is a test notification',
            data: { withSome: 'data' },
        })
    }

    let chunks = expo.chunkPushNotifications(messages);
    let tickets = [];
    (async () => {
        for (let chunk of chunks) {
            try {
               console.log('about to send')
                let ticketChunk = await expo.sendPushNotificationsAsync(chunk);
                console.log('back from send')
                console.log(ticketChunk)
                tickets.push(...ticketChunk);
                console.log('ticket chunk pushed')
            } catch (error) {
                console.log('sendPushNotificationsAsync Error')
                console.error(error);
            }
        }
    })();
}

module.exports.sendNotification = sendNotification

And my test harness that I am using to test it:

var chai = require('chai')
var PushNotification = require('../utility_modules/pushnotification')

describe('pushNotification Tests', function () {
    it('should send a notification', (done) => {
        PushNotification.sendNotification()
        done()
    })
})

Test Results:

 pushNotification Tests
about to send
testing start
    ✓ should send a notification


  1 passing (24ms)

Hopefully I’m just missing something stupid, but I can’t seem to figure it out because my test harness returns a positive test result, no errors are generated, and the notification is never sent. Any help would be greatly appreciated.

Have you tested this from the Node REPL or another environment outside of a testing framework?

I just called it from a regular Expo/React-Native request to my Node.js back-end and it worked! Tried again from the test program and same result as before.

Good news and it gets me over a hump…but any idea why it doesn’t work in my Mocha/Chai test?

Could be that some modules are getting mocked or that the harness isn’t set up for asynchrony. I’d recommend stepping through the internals of the harness with a debugger to figure out what’s going on.

Ok thanks. Definitely seems to be something specific to the test harness…will let you know if/when I figure out the problem. Appreciate you getting me on the right track!

Ok, so here’s the solution I figured out. You are correct that it had to do with the ASYNC calls

First here is my new test harness code:

var chai = require('chai')
var PushNotification = require('../utility_modules/pushnotification')
var config = require('../config')
// Test Variables

describe('pushNotification Tests', function () {
    it('should send a notification', () => {
        return new Promise((resolve) => {
            let sendToken = {}
            sendToken.to = `ExponentPushToken[____REDACTED TOKEN____]`
            sendToken.sound = 'default'
            sendToken.body = 'This is a test notification'
            sendToken.data = { data: 'myData' }

            let tokens = []
            tokens.push(sendToken)
            PushNotification.sendNotification(tokens)
                .then(function (result) {
                    resolve(true)
                })
        })
    })
})

Second, I modified the actual push notification code to make the sendNotification async, and add await to the anonymous function within it.

const { Expo } = require('expo-server-sdk')

async function sendNotification(tokens) {
    if (tokens != null && tokens.length != null) {

        let expo = new Expo();
        let messages = [];
        for (let pushToken of tokens) {
            if (!Expo.isExpoPushToken(pushToken.to)) {
                console.error(`Push token ${pushToken} is not a valid Expo push token`);
                continue;
            }

            messages.push({
                to: pushToken.to,
                sound: pushToken.sound,
                body: pushToken.body,
                data: pushToken.data,
            })
        }
        let chunks = expo.chunkPushNotifications(messages);
        let tickets = [];
        await (async () => {
            for (let chunk of chunks) {
                try {
                    console.log('about to send')
                    //console.log(chunk)
                    let ticketChunk = await expo.sendPushNotificationsAsync(chunk);
                    console.log('back from send')
                    console.log(ticketChunk)
                    tickets.push(...ticketChunk);
                    console.log('ticket chunk pushed')
                } catch (error) {
                    console.log('sendPushNotificationsAsync Error')
                    console.error(error);
                }
            }
        })();
    } else {
        console.log('Invalid token array passed to pushnotification.sendNotification()')
    }
}

module.exports.sendNotification = sendNotification

1 Like

This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.