I have a React Native ponent which municates with a custom iOS class, so I make use of NativeModules en NativeEventEmitter to send mands to and receive mands from the native code.
import {NativeModules, NativeEventEmitter} from 'react-native';
/* inside the constructor I do some setup: */
const { NetworkManager } = NativeModules;
const emitter = new NativeEventEmitter(NetworkManager);
/* here I subscribe to an event from the emitter */
public startDiscovery() {
const deviceFoundSubscription = this._emitter.addListener(
"DeviceDiscovered",
(device) => this.deviceFound(device)
);
this.NetworkManager.startDiscovery();
}
This code works just fine, but now I wanted to write some tests with Jest and this is where I am stuck. How would I go ahead to write a test for the event listener? I want to simulate a DeviceDiscovered event in a Jest test, and then assert that the listener is called.
I have a React Native ponent which municates with a custom iOS class, so I make use of NativeModules en NativeEventEmitter to send mands to and receive mands from the native code.
import {NativeModules, NativeEventEmitter} from 'react-native';
/* inside the constructor I do some setup: */
const { NetworkManager } = NativeModules;
const emitter = new NativeEventEmitter(NetworkManager);
/* here I subscribe to an event from the emitter */
public startDiscovery() {
const deviceFoundSubscription = this._emitter.addListener(
"DeviceDiscovered",
(device) => this.deviceFound(device)
);
this.NetworkManager.startDiscovery();
}
This code works just fine, but now I wanted to write some tests with Jest and this is where I am stuck. How would I go ahead to write a test for the event listener? I want to simulate a DeviceDiscovered event in a Jest test, and then assert that the listener is called.
Share Improve this question edited May 10, 2019 at 7:23 skyboyer 23.8k7 gold badges62 silver badges71 bronze badges asked Feb 2, 2018 at 19:56 dentemmdentemm 6,3794 gold badges33 silver badges44 bronze badges 03 Answers
Reset to default 7To solve my problem I have mocked RCTDeviceEventEmitter by using an everyday JS EventEmitter:
const EventEmitter = require('EventEmitter');
const RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
/**
* Mock the NativeEventEmitter as a normal JS EventEmitter.
*/
export class NativeEventEmitter extends EventEmitter {
constructor() {
super(RCTDeviceEventEmitter.sharedSubscriber);
}
}
Than in my setupFile for jest I imported the mock to replace the react-native implementation.
import NativeEventEmitter from './__mocks__/nativeEventEmitter';
import { NativeModules } from 'react-native';
// Mock for my native module where I create a spy for the methods
const mockNativeModules = {
NetworkManager: {
startDiscovery: jest.fn(),
stopDiscovery: jest.fn(),
connectToHost: jest.fn(),
sendMessage: jest.fn()
}
};
// Mock every native module you use
Object.keys(mockNativeModules).forEach((module => {
jest.doMock(module, () => mockNativeModules[module], { virtual:true });
}));
jest.doMock('NativeModules', () => mockNativeModules);
jest.mock('NativeEventEmitter');
And than finally my actual test code:
import {
NativeModules,
NativeEventEmitter,
} from 'react-native';
import { DiscoveryService } from '/services/discoveryService';
import { device1, device2 } from './../fixtures/devices';
const nativeEventEmitter = new NativeEventEmitter();
describe('Discovery Service', () => {
beforeEach(() => {
discoveryService.deviceDiscovered = jest.fn();
discoveryService.startDiscovery();
});
test('Should call startDiscovery on Native Module NetworkManager', () => {
nativeEventEmitter.emit('DeviceDiscovered', device);
expect(NativeModules.NetworkManager.startDiscovery).toHaveBeenCalledTimes(1);
expect(discoveryService.serverFound).toHaveBeenCalledWith(device1);
});
test('Should handle multiple discoveries', () => {
nativeEventEmitter.emit('DeviceDiscovered', device1);
expect(discoveryService.serverFound).toHaveBeenCalledWith(device1);
nativeEventEmitter.emit('DeviceDiscovered', device2)
expect(discoveryService.deviceFound).toHaveBeenCalledWith(device2);
});
});
in your jest/setup.js
add your relative path:
jest.mock(
'../node_modules/react-native/Libraries/EventEmitter/NativeEventEmitter',
);
jest.mock('react-native/Libraries/EventEmitter/NativeEventEmitter.js', () => {
const { EventEmitter } = require('events');
return EventEmitter;
});