Mocking Permissions, Sensors & Device Behaviors in Jest
šļø When Your App Wants to Notify the Userā¦
Mocking Permissions, Sensors & Device Behaviors inĀ Jest

šļø When Your App Wants to Notify the Userā¦
Our Expense Tracker is now a grown-up app.
It calculates totalsā¦
fetches APIsā¦
survives network disastersā¦
and even remembers things better than we do.
So now it wants to do something meaningful:
š Remind the user to add expenses.
But thereās a problem.
A UNIVERSAL problem.
The user.
May.
Say.
āNO.ā
Yes.
Notification permissions are that polite request your app makesā¦
and the user rejects like a spam call.
So today we learn to mock notification permissions, so your tests do not break when real users decide to betray you.
š” Why Notification Permissions NeedĀ Mocking

In real apps, notifications break for reasons nobody understands:
- The user denied permission
- iOS silently blocks your request
- Android āoptimizes batteryā (translation: kills everything)
- Notification service returns empty responses
- Some devices delay notifications by 6 hours
- Some fire twice
- Some never fire at all
Testing this in real life is impossible.
Testing in Jest?
Easy.
Fast.
Predictable.
And you do not need 12 devices on your desk.
š§Ŗ Step 1āāāOur Notification Permission Function
Letās say our Expense Tracker checks permission before sending reminders:
š notificationPermission.js
exports.checkNotificationPermission = async () => {
return Notification.requestPermission();
};In browsers this returns "granted", "denied", or "default".
On devices, libraries like Expo/React Native behave similarly.
We want to test how our logic reacts to each state.
š§Ŗ Step 2āāāMock the Permission API
š notificationPermission.test.js
global.Notification = {
requestPermission: jest.fn(),
};
const { checkNotificationPermission } = require('./notificationPermission');
test('should handle granted permission', async () => {
Notification.requestPermission.mockResolvedValue('granted');
const result = await checkNotificationPermission();
expect(result).toBe('granted');
});This is clean.
Simple.
Predictable.
And you never have to rely on real OS permission dialogs.
You have definitely seen this:
You test notifications on Android.
Ā They work.
Ā You test on iOS.
Ā They donāt.
Ā You test again.
Ā They work.
Ā You hand the device to QA.
Ā They stop working.
You reinstall the app.
Ā They work again.
Ā You push to production.
Ā They never work again.
Mocking avoids this emotional rollercoaster.
š§Ŗ Step 3āāāMock āDeniedā Permission
test('should handle denied permission', async () => {
Notification.requestPermission.mockResolvedValue('denied');
const result = await checkNotificationPermission();
expect(result).toBe('denied');
});Your app should gracefully handle a user who says āno thanks.ā
š§Ŗ Step 4āāāMock āDefaultā (User IgnoredĀ Prompt)
On web and some RN libs, "default" means user dismissed the popup without answering.
test('should handle default permission', async () => {
Notification.requestPermission.mockResolvedValue('default');
const result = await checkNotificationPermission();
expect(result).toBe('default');
});This case is often forgottenāāābut very real.
š„ Step 5āāāMocking Actual Notification Delivery
Imagine this function:
š sendNotification.js
exports.sendReminder = async () => {
if (Notification.permission !== 'granted') return false;
return Notification.show('Time to log expenses!');
};We mock this too:
global.Notification = {
permission: 'granted',
show: jest.fn(),
};
const { sendReminder } = require('./sendNotification');
test('should send notification when permission granted', async () => {
const result = await sendReminder();
expect(Notification.show).toHaveBeenCalled();
expect(result).toBeTruthy();
});Now you test the entire flow:
permission ā delivery ā success.
Psychology

Developers relate deeply to notification bugs because:
- They think itās working (itās not)
- They think itās not working (it suddenly is)
- iOS Simulator lies
- Android background restrictions change every OS update
- Expoās notification service behaves differently across devices
When your writing points to these experiences, readers feel:
āYESāāāIāve suffered this too.ā
And thatās why they keep reading your series.
This is how you build trust.
ā SUMMARY

Today our Expense Tracker learned how to talk to the user politelyā¦
and how to survive emotional rejection.
We learned:
Ā šļø Mocking notification permissions (granted / denied / default)
Ā š© Mocking actual notification delivery
Ā ā Avoiding OS-level unpredictability
Ā š Making tests consistent across devices
Your tests now understand human behavior:
Most people say āNot Now.ā
Your app says āNo problem.ā
Next post ā Mocking Sensors & Device Behaviors (GPS, Motion, Orientation)
Weāre going deeper.
Thanks forĀ reading.
If this added value, follow me for more clear and practical posts.
ā Alkesh Jethava