I am trying to mock Firebase Cloud Messaging (FCM), from #react-native-firebase/messaging.So far here is my mock:
jest.mock('#react-native-firebase/messaging', () => ({
hasPermission: jest.fn(() => Promise.resolve(true)),
subscribeToTopic: jest.fn(),
deleteToken: jest.fn(),
unsubscribeFromTopic: jest.fn(),
registerForRemoteNotifications: jest.fn(),
requestPermission: jest.fn(() => Promise.resolve(true)),
getToken: jest.fn(() => Promise.resolve('myMockToken')),
getAPNSToken: jest.fn(() => Promise.resolve('myMockToken')),
onTokenRefresh: jest.fn(() => Promise.resolve('myMockToken')),
onMessage: jest.fn(),
isRegisteredForRemoteNotifications: jest.mock(false),
isAutoInitEnabled: jest.mock(false),
}));
But when I run my test I get:
Invariant Violation: Native module cannot be null.
at invariant (packages/mobile/node_modules/invariant/invariant.js:40:15)
at RNFBNativeEventEmitter.invariant (packages/mobile/node_modules/react-native/Libraries/EventEmitter/NativeEventEmitter.js:36:7)
at new RNFBNativeEventEmitter (node_modules/#react-native-firebase/messaging/node_modules/#react-native-firebase/app/lib/internal/RNFBNativeEventEmitter.js:24:5)
at Object.<anonymous> (node_modules/#react-native-firebase/messaging/node_modules/#react-native-firebase/app/lib/internal/RNFBNativeEventEmitter.js:48:16)
at Object.<anonymous> (node_modules/#react-native-firebase/messaging/node_modules/#react-native-firebase/app/lib/internal/registry/nativeModule.js:21:1)
Which tells me that I still have to mock some other functions. What am I missing in here?
I turn out that I was not mocking properly. I created a
__mocks__/#react-native-firebase/messaging.js.
In that file I write:
module.exports = {
hasPermission: jest.fn(() => Promise.resolve(true)),
subscribeToTopic: jest.fn(),
unsubscribeFromTopic: jest.fn(),
requestPermission: jest.fn(() => Promise.resolve(true)),
getToken: jest.fn(() => Promise.resolve('myMockToken')),
};
Also In my setup jest I have:
reactNative.NativeModules.RNCNetInfo = {
getCurrentState: jest.fn(() => Promise.resolve()),
addListener: jest.fn(),
removeListeners: jest.fn(),
};
Related
app.component.ts:->
`if (Capacitor.isPluginAvailable('Keyboard')) {
this.keypadOpenListner = Keyboard.addListener('keyboardDidShow', () => {
this.zone.run(() => {
this.isKeyboardShowing = true;
})
});
this.keypadOffListner = Keyboard.addListener('keyboardDidHide', () => {
this.zone.run(() => {
this.isKeyboardShowing = false;
})
});
}`
`
app.component.spec.ts:->
` describe('app compenent', () => {
let fixture: ComponentFixture<AppComponent>;
let component: AppComponent;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [AppComponent]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(AppComponent);
component = fixture.componentInstance;
spyOn(Capacitor, 'isNativePlatform').and.returnValue(true);
fixture.detectChanges();
});`
to cover if condition I added spyOn(Capacitor, 'isNativePlatform').and.returnValue(true); in beforeEach condition is this correct? if yes I got warning "Keyboard" plugin is not implemented on web how can I overcomethe warning ?.
I'm trying to run a unity test on a method by mocking an addressList but it says that it cannot read the property of undefined.
The method:
async paginate(
user: User,
options: IPaginationOptions,
): Promise<Pagination<AddressResponse>> {
const pagination = await this.addressRepository.paginate(user, options);
return new Pagination(
await Promise.all(
pagination.items.map(async (address) => new AddressResponse(address)),
),
pagination.meta,
pagination.links,
);
}
The problem is, when I put a console.log() to read the variable "pagination" it shows me an array that is not empty on the concole:
console.log
addressList: [ Address {} ]
this is what the repository is returning to me.
The test that I'm trying to run is this one:
describe('AddressService', () => {
let addressService: AddressService;
const user = new User();
const addressList: Address[] = [new Address()];
console.log('addressList: ', addressList);
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
AddressService,
{
provide: getRepositoryToken(AddressRepository),
useValue: {
paginate: jest.fn().mockResolvedValue(addressList),
create: jest.fn(),
save: jest.fn(),
findById: jest.fn(),
findOne: jest.fn(),
update: jest.fn(),
delete: jest.fn(),
},
},
],
}).compile();
addressService = module.get<AddressService>(AddressService);
});
it('should be defined', () => {
expect(addressService).toBeDefined();
});
describe('paginate', () => {
it('should return an address list successfully', async () => {
// Act
const result = await addressService.paginate(user, {
page: 1,
limit: 10,
});
// Assert
expect(result).toEqual(addressList);
});
});
});
What is the issue with my code? I'm trying to fix this by days.
Your paginate variable is indeed defined and populated, but the property you first accecss in the code is not. You try to access paginate.items while your mock just returns an array of Address. Change your paginate mock to be paginate: jest.fn().mockResolvedValue({ items: addressList }) and it should be fixed
I am facing an issue when calling mock service inside beforeEach function.
To make get the access token from the login so i need to run this mock service for all the function in the spec file so that we can make it run this in an orderly manner.
beforeEach(inject([LoginService, MockBackend], (Service: LoginService, mockBackend: MockBackend) => {
loginService = Service;
backend = mockBackend;
it('#login should call endpoint and return it\'s result', (done) => {
backend.connections.subscribe((connection: MockConnection) => {
const options = new ResponseOptions({
body: JSON.stringify({ success: true })
});
connection.mockRespond(new Response(options));
// Check the request headers
expect(connection.request.headers.get('Content-Type')).toEqual('application/json');
});
loginService.login('new', 'secret')
.subscribe((response) => {
sessionStorage.setItem('token', JSON.stringify(response.token));
done();
fixture = TestBed.createComponent(DashboardComponent);
router.initialNavigation();
component = fixture.componentInstance;
fixture.detectChanges();
},
(error) => {
expect(error).toThrowError();
});
});
}));
I'm writing an app with React Native. I use Firebase Cloud Messaging for real time communication. I'm currently writing the unit tests for the FCM code using jest. The problem is that I'm struggling to make it work, since it consists of void functions that contain promises. Let me give you the code:
fcm.js:
import { Alert } from "react-native";
import firebase from "react-native-firebase";
export const checkNotificationsPermission = () => {
firebase
.messaging()
.hasPermission()
.then(enabled => {
if (enabled) {
// User has permissions.
} else {
// User doesn't have permission.
Alert.alert(
alertMessages.firebasePrepareForPermissionTitle,
alertMessages.firebasePrepareForPermissionMessage,
[{ text: buttonTexts.ok, onPress: () => requestNotificationsPermission() }]
);
}
});
};
export const requestNotificationsPermission = () => {
firebase
.messaging()
.requestPermission()
.then(() => {
// User has authorised.
})
.catch(() => {
// User has rejected permissions.
Alert.alert(
alertMessages.firebasePrepareForPermissionTitle,
alertMessages.firebasePermissionDeniedMessage,
[{ text: buttonTexts.ok, onPress: () => {} }]
);
});
};
fcm.test.js:
import firebase from "react-native-firebase";
describe("checkNotificationsPermission", () => {
beforeEach(() => {
return checkNotificationsPermission();
});
afterEach(() => {
jest.clearAllMocks();
});
it("should call firebase's hasPermission", async () => {
expect(firebase.messaging().requestPermission).toHaveBeenCalledTimes(1);
});
});
Here is how I mocked firebase (__mocks__/react-native-firebase.js):
const firebase = {
messaging: jest.fn(() => ({
hasPermission: jest.fn(() => new Promise(resolve => resolve(true))),
requestPermission: jest.fn(() => new Promise(resolve => resolve(true)))
}))
};
export default firebase;
The test fails with Expected mock function to have been called one time, but it was called zero times..Since this wouldn't work and I had a similar question about promises which got answered I tried to apply what I learned there which resulted in the following code.
fcm.js:
import { Alert } from "react-native";
import firebase from "react-native-firebase";
export const checkNotificationsPermission = () =>
new Promise((resolve, reject) => {
firebase
.messaging()
.hasPermission()
.then(enabled => {
if (enabled) {
// User has permissions.
resolve(true);
} else {
// User doesn't have permission.
Alert.alert(
alertMessages.firebasePrepareForPermissionTitle,
alertMessages.firebasePrepareForPermissionMessage,
[
{
text: buttonTexts.ok,
onPress: () =>
requestNotificationsPermission()
.then(() => resolve(true))
.catch(() => reject(false))
}
]
);
}
});
});
export const requestNotificationsPermission = () =>
new Promise((resolve, reject) => {
firebase
.messaging()
.requestPermission()
.then(() => {
// User has authorised.
resolve(true);
})
.catch(() => {
// User has rejected permissions.
reject(true);
Alert.alert(
alertMessages.firebasePrepareForPermissionTitle,
alertMessages.firebasePermissionDeniedMessage,
[{ text: buttonTexts.ok, onPress: () => {} }]
);
});
});
fcm.test.js:
import firebase from "react-native-firebase";
import { requestNotifcationsPermission } from "./fcm";
describe("checkNotificationsPermission", () => {
afterEach(() => {
jest.clearAllMocks();
});
it("should call firebase's hasPermission", () => {
expect.assertions(1);
return checkNotificationsPermission().then(() => {
expect(firebase.messaging().requestPermission).toHaveBeenCalledTimes(1);
});
});
});
But for some reason these tests still fail. I empirically tested and ensured the code works. Just the unit tests won't pass.
Edit
I accidentally left out that both fcm.js also have the following imports:
import alertMessages from "../../config/constants/alertMessages";
import buttonTexts from "../../config/constants/buttonTexts";
I am trying to mock the pg promise library. I want to be able mock return whether the promise rejects or resolves. Here is an example function and test:
const pgp = require('pg-promise')({});
const someFunc = callback => {
const db = pgp('connectionString');
db
.none('create database test;')
.then(() => {
callback(null, 'success');
})
.catch(err => {
callback(err);
});
};
module.exports = {
someFunc
};
And i wanna test it like so:
const { someFunc } = require('./temp');
let pgp = require('pg-promise')({
noLocking: true
});
// HOW TO MOCK?
describe('test', () => {
beforeEach(() => {
jest.resetModules();
jest.resetAllMocks();
});
it('should test', () => {
let db = pgp('connectionString');
// how to mock this?
db.none = jest.fn();
db.none.mockReturnValue(Promise.reject('mock'));
const callback = jest.fn();
someFunc(callback);
return new Promise(resolve => setImmediate(resolve)).then(() => {
expect(callback.mock.calls.length).toEqual(1);
});
});
});
You can mock the pgp object with a dumb mock like so:
const { someFunc } = require('./temp');
let pgp = jest.fn(() => ({
none: jest.fn(),
})
jest.mock('pg-promise') // Jest will hoist this line to the top of the file
// and prevent you from accidentially calling the
// real package.
describe('test', () => {
beforeEach(() => {
jest.resetModules();
jest.resetAllMocks();
});
it('should test', () => {
let db = pgp('connectionString');
db.none.mockRejectedValue('mock'); // This is the mock
const callback = jest.fn();
someFunc(callback);
return new Promise(resolve => setImmediate(resolve)).then(() => {
expect(callback.mock.calls.length).toEqual(1);
});
});
});
Its an old question, but here is a new answer:
You can have a look at pg-mem, a library I released recently which emulates an in-memory postgres instance.
It supports most of the usual SQL queries (but will fail on less frequent syntaxes - file an issue if you encounter such a situation).
I wrote an article about it here
For your use case, see the this section