react-native/Libraries/Utilities/__tests__/MessageQueue-test.js
Christoph Pojer 89a9ca6688 Update some JS in preparation for some Jest updates.
Summary:
* Next version of Jest doesn't allow non test files in __tests__ folders.
* I'm trying to switch all tests off of jsdom on react-native. This should save 500ms of time when running a single test because jsdom is slow to load and react-native is also not supposed to run in a DOM environment, so let's not pretend we are providing the DOM in tests.
* Make the bridge config configurable so that when we disable automocking and we reset the registry we can redefine the value.

Oh also, stop using lodash in Server.js. First off, lodash 3 doesn't work in Jest's node env because it does some crazy stuff, second because we don't need to load all of lodash for debounce.

Reviewed By: davidaurelio

Differential Revision: D3502886

fbshipit-source-id: 1da1cfba9ed12264d81945b702e7a429d5f84424
2016-06-30 01:58:40 -07:00

198 lines
7.1 KiB
JavaScript

/**
* Copyright (c) 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
'use strict';
const MessageQueueTestConfig = require('MessageQueueTestConfig');
jest.unmock('MessageQueue');
let MessageQueue;
let MessageQueueTestModule1;
let MessageQueueTestModule2;
let queue;
const MODULE_IDS = 0;
const METHOD_IDS = 1;
const PARAMS = 2;
const assertQueue = (flushedQueue, index, moduleID, methodID, params) => {
expect(flushedQueue[MODULE_IDS][index]).toEqual(moduleID);
expect(flushedQueue[METHOD_IDS][index]).toEqual(methodID);
expect(flushedQueue[PARAMS][index]).toEqual(params);
};
// Important things to test:
//
// [x] Calling remote method on queue actually queues it up.
//
// [x] Both error and success callbacks are invoked.
//
// [x] When simulating an error callback from remote method, both error and
// success callbacks are cleaned up.
//
// [x] Local modules can be invoked through the queue.
//
// [ ] Local modules that throw exceptions are gracefully caught. In that case
// local callbacks stored by IDs are cleaned up.
//
// [ ] Remote invocation throws if not supplying an error callback.
describe('MessageQueue', function() {
beforeEach(function() {
jest.resetModuleRegistry();
MessageQueue = require('MessageQueue');
MessageQueueTestModule1 = require('MessageQueueTestModule1');
MessageQueueTestModule2 = require('MessageQueueTestModule2');
queue = new MessageQueue(
() => MessageQueueTestConfig
);
queue.registerCallableModule(
'MessageQueueTestModule1',
MessageQueueTestModule1
);
queue.registerCallableModule(
'MessageQueueTestModule2',
MessageQueueTestModule2
);
});
it('should enqueue native calls', () => {
queue.__nativeCall(0, 1, [2]);
let flushedQueue = queue.flushedQueue();
assertQueue(flushedQueue, 0, 0, 1, [2]);
});
it('should call a local function with the function name', () => {
MessageQueueTestModule1.testHook2 = jasmine.createSpy();
expect(MessageQueueTestModule1.testHook2.calls.count()).toEqual(0);
queue.__callFunction('MessageQueueTestModule1', 'testHook2', [2]);
expect(MessageQueueTestModule1.testHook2.calls.count()).toEqual(1);
});
it('should generate native modules', () => {
queue.RemoteModules.RemoteModule1.remoteMethod1('foo');
let flushedQueue = queue.flushedQueue();
assertQueue(flushedQueue, 0, 0, 0, ['foo']);
});
it('should store callbacks', () => {
queue.RemoteModules.RemoteModule1.remoteMethod2('foo', () => {}, () => {});
let flushedQueue = queue.flushedQueue();
assertQueue(flushedQueue, 0, 0, 1, ['foo', 0, 1]);
});
it('should call the stored callback', () => {
var done = false;
queue.RemoteModules.RemoteModule1.remoteMethod1(() => { done = true; });
queue.__invokeCallback(1);
expect(done).toEqual(true);
});
it('should throw when calling the same callback twice', () => {
queue.RemoteModules.RemoteModule1.remoteMethod1(() => {});
queue.__invokeCallback(1);
expect(() => queue.__invokeCallback(1)).toThrow();
});
it('should throw when calling both success and failure callback', () => {
queue.RemoteModules.RemoteModule1.remoteMethod1(() => {}, () => {});
queue.__invokeCallback(1);
expect(() => queue.__invokeCallback(0)).toThrow();
});
it('should make round trip and clear memory', function() {
// Perform communication
// First we're going to call into this (overriden) test hook pretending to
// be a remote module making a "local" invocation into JS.
let onFail = jasmine.createSpy();
let onSucc = jasmine.createSpy();
MessageQueueTestModule1.testHook1 = function() {
// Then inside of this local module, we're going to fire off a remote
// request.
queue.__nativeCall(
0,
0,
Array.prototype.slice.apply(arguments),
onFail,
onSucc,
);
};
// The second test hook does the same thing as the first, but fires off a
// remote request to a different remote module/method.
MessageQueueTestModule1.testHook2 = function() {
queue.__nativeCall(
1,
1,
Array.prototype.slice.apply(arguments),
onFail,
onSucc,
);
};
/* MessageQueueTestModule1.testHook1 */
queue.__callFunction('MessageQueueTestModule1', 'testHook1', ['paloAlto', 'menloPark']);
/* MessageQueueTestModule1.testHook2 */
queue.__callFunction('MessageQueueTestModule1', 'testHook2', ['mac', 'windows']);
// And how do we know that it executed those local modules correctly? Well,
// these particular test method echo their arguments back to remote methods!
var resultingRemoteInvocations = queue.flushedQueue();
// As always, the message queue has five fields
expect(resultingRemoteInvocations.length).toBe(4);
expect(resultingRemoteInvocations[0].length).toBe(2);
expect(resultingRemoteInvocations[1].length).toBe(2);
expect(resultingRemoteInvocations[2].length).toBe(2);
expect(typeof resultingRemoteInvocations[3]).toEqual('number');
expect(resultingRemoteInvocations[0][0]).toBe(0); // `RemoteModule1`
expect(resultingRemoteInvocations[1][0]).toBe(0); // `remoteMethod1`
expect([ // the arguments
resultingRemoteInvocations[2][0][0],
resultingRemoteInvocations[2][0][1]
]).toEqual(['paloAlto', 'menloPark']);
// Callbacks ids are tacked onto the end of the remote arguments.
var firstFailCBID = resultingRemoteInvocations[2][0][2];
var firstSuccCBID = resultingRemoteInvocations[2][0][3];
expect(resultingRemoteInvocations[0][1]).toBe(1); // `RemoteModule2`
expect(resultingRemoteInvocations[1][1]).toBe(1); // `remoteMethod2`
expect([ // the arguments
resultingRemoteInvocations[2][1][0],
resultingRemoteInvocations[2][1][1]
]).toEqual(['mac', 'windows']);
var secondFailCBID = resultingRemoteInvocations[2][1][2];
var secondSuccCBID = resultingRemoteInvocations[2][1][3];
// Trigger init
queue.RemoteModules
// Handle the first remote invocation by signaling failure.
// -------------------------------------------------------
queue.__invokeCallback(firstFailCBID, ['firstFailure']);
// The failure callback was already invoked, the success is no longer valid
expect(function() {
queue.__invokeCallback(firstSuccCBID, ['firstSucc']);
}).toThrow();
expect(onFail.calls.count()).toBe(1);
expect(onSucc.calls.count()).toBe(0);
// Handle the second remote invocation by signaling success.
// -------------------------------------------------------
queue.__invokeCallback(secondSuccCBID, ['secondSucc']);
// The success callback was already invoked, the fail cb is no longer valid
expect(function() {
queue.__invokeCallback(secondFailCBID, ['secondFail']);
}).toThrow();
expect(onFail.calls.count()).toBe(1);
expect(onSucc.calls.count()).toBe(1);
});
});