relay-test-utils
Version:
Utilities for testing Relay applications.
323 lines (322 loc) • 14.3 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault")["default"];
var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
var areEqual = require("fbjs/lib/areEqual");
var invariant = require('invariant');
var _require = require('relay-runtime'),
Environment = _require.Environment,
Network = _require.Network,
Observable = _require.Observable,
QueryResponseCache = _require.QueryResponseCache,
RecordSource = _require.RecordSource,
Store = _require.Store,
createOperationDescriptor = _require.createOperationDescriptor,
getRequest = _require.getRequest;
var MAX_SIZE = 10;
var MAX_TTL = 5 * 60 * 1000;
function mockInstanceMethod(object, key) {
object[key] = jest.fn(object[key].bind(object));
}
function mockDisposableMethod(object, key) {
var fn = object[key].bind(object);
object[key] = jest.fn(function () {
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
var disposable = fn.apply(void 0, args);
var dispose = jest.fn(function () {
return disposable.dispose();
});
object[key].mock.dispose = dispose;
return {
dispose: dispose
};
});
var mockClear = object[key].mockClear.bind(object[key]);
object[key].mockClear = function () {
mockClear();
object[key].mock.dispose = null;
};
}
function mockObservableMethod(object, key) {
var fn = object[key].bind(object);
var subscriptions = [];
object[key] = jest.fn(function () {
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
return fn.apply(void 0, args)["do"]({
start: function start(subscription) {
subscriptions.push(subscription);
}
});
});
object[key].mock.subscriptions = subscriptions;
var mockClear = object[key].mockClear.bind(object[key]);
object[key].mockClear = function () {
mockClear();
object[key].mock.subscriptions = [];
};
}
function createMockEnvironment(config) {
var _config$store, _global, _global$process, _global$process$env;
var store = (_config$store = config === null || config === void 0 ? void 0 : config.store) !== null && _config$store !== void 0 ? _config$store : new Store(new RecordSource());
var cache = new QueryResponseCache({
size: MAX_SIZE,
ttl: MAX_TTL
});
var pendingRequests = [];
var pendingOperations = [];
var queuePendingOperation = function queuePendingOperation(query, variables) {
var operationDescriptor = createOperationDescriptor(getRequest(query), variables);
pendingOperations = pendingOperations.concat([operationDescriptor]);
};
var resolversQueue = [];
var queueOperationResolver = function queueOperationResolver(resolver) {
resolversQueue = resolversQueue.concat([resolver]);
};
var execute = function execute(request, variables, cacheConfig) {
var id = request.id,
text = request.text;
var cacheID = id !== null && id !== void 0 ? id : text;
var cachedPayload = null;
if (((cacheConfig === null || cacheConfig === void 0 ? void 0 : cacheConfig.force) == null || (cacheConfig === null || cacheConfig === void 0 ? void 0 : cacheConfig.force) === false) && cacheID != null) {
cachedPayload = cache.get(cacheID, variables);
}
if (cachedPayload !== null) {
return Observable.from(cachedPayload);
}
var currentOperation = pendingOperations.find(function (op) {
return op.request.node.params === request && areEqual(op.request.variables, variables);
});
if (currentOperation != null && resolversQueue.length > 0) {
var currentResolver = resolversQueue[0];
var result = currentResolver(currentOperation);
if (result != null) {
resolversQueue = resolversQueue.filter(function (res) {
return res !== currentResolver;
});
pendingOperations = pendingOperations.filter(function (op) {
return op !== currentOperation;
});
if (result instanceof Error) {
return Observable.create(function (sink) {
sink.error(result);
});
} else {
return Observable.from(result);
}
}
}
return Observable.create(function (sink) {
var nextRequest = {
request: request,
variables: variables,
cacheConfig: cacheConfig,
sink: sink
};
pendingRequests = pendingRequests.concat([nextRequest]);
return function () {
pendingRequests = pendingRequests.filter(function (pending) {
return !areEqual(pending, nextRequest);
});
var currentOperation = pendingOperations.find(function (op) {
return areEqual(op.request.node.params, request) && areEqual(op.request.variables, variables);
});
pendingOperations = pendingOperations.filter(function (op) {
return op !== currentOperation;
});
};
});
};
function getConcreteRequest(input) {
if (input.kind === 'Request') {
var request = input;
return request;
} else {
var operationDescriptor = input;
!pendingOperations.includes(operationDescriptor) ? process.env.NODE_ENV !== "production" ? invariant(false, 'RelayModernMockEnvironment: Operation "%s" was not found in the list of pending operations', operationDescriptor.request.node.operation.name) : invariant(false) : void 0;
return operationDescriptor.request.node;
}
}
function getRequests(input) {
var concreteRequest;
var operationDescriptor;
if (input.kind === 'Request') {
concreteRequest = input;
} else {
operationDescriptor = input;
concreteRequest = operationDescriptor.request.node;
}
var foundRequests = pendingRequests.filter(function (pending) {
if (!areEqual(pending.request, concreteRequest.params)) {
return false;
}
if (operationDescriptor) {
return areEqual(operationDescriptor.request.variables, pending.variables);
} else {
return true;
}
});
!foundRequests.length ? process.env.NODE_ENV !== "production" ? invariant(false, 'MockEnvironment: Cannot respond to request, it has not been requested yet.') : invariant(false) : void 0;
foundRequests.forEach(function (foundRequest) {
!foundRequest.sink ? process.env.NODE_ENV !== "production" ? invariant(false, 'MockEnvironment: Cannot respond to `%s`, it has not been requested yet.', concreteRequest.params.name) : invariant(false) : void 0;
});
return foundRequests;
}
function ensureValidPayload(payload) {
!(typeof payload === 'object' && payload !== null && payload.hasOwnProperty('data')) ? process.env.NODE_ENV !== "production" ? invariant(false, 'MockEnvironment(): Expected payload to be an object with a `data` key.') : invariant(false) : void 0;
return payload;
}
var cachePayload = function cachePayload(request, variables, payload) {
var _getConcreteRequest$p = getConcreteRequest(request).params,
id = _getConcreteRequest$p.id,
text = _getConcreteRequest$p.text;
var cacheID = id !== null && id !== void 0 ? id : text;
!(cacheID != null) ? process.env.NODE_ENV !== "production" ? invariant(false, 'CacheID should not be null') : invariant(false) : void 0;
cache.set(cacheID, variables, payload);
};
var clearCache = function clearCache() {
cache.clear();
};
var isLoading = function isLoading(request, variables, cacheConfig) {
return pendingRequests.some(function (pending) {
return areEqual(pending.request, getConcreteRequest(request).params) && areEqual(pending.variables, variables) && areEqual(pending.cacheConfig, cacheConfig !== null && cacheConfig !== void 0 ? cacheConfig : {});
});
};
var reject = function reject(request, error) {
var rejectError = typeof error === 'string' ? new Error(error) : error;
getRequests(request).forEach(function (foundRequest) {
var sink = foundRequest.sink;
!(sink !== null) ? process.env.NODE_ENV !== "production" ? invariant(false, 'Sink should be defined.') : invariant(false) : void 0;
sink.error(rejectError);
});
};
var nextValue = function nextValue(request, payload) {
getRequests(request).forEach(function (foundRequest) {
var sink = foundRequest.sink;
!(sink !== null) ? process.env.NODE_ENV !== "production" ? invariant(false, 'Sink should be defined.') : invariant(false) : void 0;
sink.next(ensureValidPayload(payload));
});
};
var complete = function complete(request) {
getRequests(request).forEach(function (foundRequest) {
var sink = foundRequest.sink;
!(sink !== null) ? process.env.NODE_ENV !== "production" ? invariant(false, 'Sink should be defined.') : invariant(false) : void 0;
sink.complete();
});
};
var resolve = function resolve(request, response) {
getRequests(request).forEach(function (foundRequest) {
var sink = foundRequest.sink;
!(sink !== null) ? process.env.NODE_ENV !== "production" ? invariant(false, 'Sink should be defined.') : invariant(false) : void 0;
var payloads = Array.isArray(response) ? response : [response];
payloads.forEach(function (payload) {
sink.next(ensureValidPayload(payload));
});
sink.complete();
});
};
var getMostRecentOperation = function getMostRecentOperation() {
var mostRecentOperation = pendingOperations[pendingOperations.length - 1];
!(mostRecentOperation != null) ? process.env.NODE_ENV !== "production" ? invariant(false, 'RelayModernMockEnvironment: There are no pending operations in the list') : invariant(false) : void 0;
return mostRecentOperation;
};
var findOperation = function findOperation(findFn) {
var pendingOperation = pendingOperations.find(findFn);
!(pendingOperation != null) ? process.env.NODE_ENV !== "production" ? invariant(false, 'RelayModernMockEnvironment: Operation was not found in the list of pending operations') : invariant(false) : void 0;
return pendingOperation;
};
var environment = new Environment((0, _objectSpread2["default"])({
configName: 'RelayModernMockEnvironment',
network: Network.create(execute, execute),
store: store
}, config));
var createExecuteProxy = function createExecuteProxy(env, fn) {
return function () {
for (var _len3 = arguments.length, argumentsList = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
argumentsList[_key3] = arguments[_key3];
}
var operation = argumentsList[0].operation;
pendingOperations = pendingOperations.concat([operation]);
return fn.apply(env, argumentsList);
};
};
environment.execute = createExecuteProxy(environment, environment.execute);
environment.executeSubscription = createExecuteProxy(environment, environment.executeSubscription);
environment.executeWithSource = createExecuteProxy(environment, environment.executeWithSource);
environment.executeMutation = createExecuteProxy(environment, environment.executeMutation);
if (((_global = global) === null || _global === void 0 ? void 0 : (_global$process = _global.process) === null || _global$process === void 0 ? void 0 : (_global$process$env = _global$process.env) === null || _global$process$env === void 0 ? void 0 : _global$process$env.NODE_ENV) === 'test') {
mockDisposableMethod(environment, 'applyUpdate');
mockInstanceMethod(environment, 'commitPayload');
mockInstanceMethod(environment, 'getStore');
mockInstanceMethod(environment, 'lookup');
mockInstanceMethod(environment, 'check');
mockDisposableMethod(environment, 'subscribe');
mockDisposableMethod(environment, 'retain');
mockObservableMethod(environment, 'execute');
mockObservableMethod(environment, 'executeSubscription');
mockObservableMethod(environment, 'executeWithSource');
mockObservableMethod(environment, 'executeMutation');
mockInstanceMethod(store, 'getSource');
mockInstanceMethod(store, 'lookup');
mockInstanceMethod(store, 'notify');
mockInstanceMethod(store, 'publish');
mockDisposableMethod(store, 'retain');
mockDisposableMethod(store, 'subscribe');
}
var mock = {
cachePayload: cachePayload,
clearCache: clearCache,
isLoading: isLoading,
reject: reject,
resolve: resolve,
nextValue: nextValue,
complete: complete,
getMostRecentOperation: getMostRecentOperation,
resolveMostRecentOperation: function resolveMostRecentOperation(payload) {
var operation = getMostRecentOperation();
var data = typeof payload === 'function' ? payload(operation) : payload;
return resolve(operation, data);
},
rejectMostRecentOperation: function rejectMostRecentOperation(error) {
var operation = getMostRecentOperation();
var rejector = typeof error === 'function' ? error(operation) : error;
return reject(operation, rejector);
},
findOperation: findOperation,
queuePendingOperation: queuePendingOperation,
getAllOperations: function getAllOperations() {
return pendingOperations;
},
queueOperationResolver: queueOperationResolver
};
environment.mock = mock;
environment.mockClear = function () {
var _store$getSource$clea, _store$getSource;
environment.applyUpdate.mockClear();
environment.commitPayload.mockClear();
environment.getStore.mockClear();
environment.lookup.mockClear();
environment.check.mockClear();
environment.subscribe.mockClear();
environment.retain.mockClear();
environment.execute.mockClear();
environment.executeMutation.mockClear();
environment.executeSubscription.mockClear();
(_store$getSource$clea = (_store$getSource = store.getSource()).clear) === null || _store$getSource$clea === void 0 ? void 0 : _store$getSource$clea.call(_store$getSource);
store.getSource.mockClear();
store.lookup.mockClear();
store.notify.mockClear();
store.publish.mockClear();
store.retain.mockClear();
store.subscribe.mockClear();
cache.clear();
pendingOperations = [];
pendingRequests = [];
};
return environment;
}
module.exports = {
createMockEnvironment: createMockEnvironment
};