oneEventLoopTestConfig = function (readableIDToID) {
  const ret = {
    // Negotiation
    scrollShouldSetResponder: {bubbled: {}, captured: {}},
    startShouldSetResponder: {bubbled: {}, captured: {}},
    moveShouldSetResponder: {bubbled: {}, captured: {}},
    responderTerminationRequest: {},

    // Non-negotiation
    responderReject: {}, // These do not bubble capture.
    responderGrant: {},
    responderStart: {},
    responderMove: {},
    responderTerminate: {},
    responderEnd: {},
    responderRelease: {},
  };
  for (const eventName in ret) {
    for (const readableNodeName in readableIDToID) {
      if (ret[eventName].bubbled) {
        // Two phase
        ret[eventName].bubbled[readableNodeName] = {
          order: NA,
          assertEvent: null,
          returnVal: undefined,
        };
        ret[eventName].captured[readableNodeName] = {
          order: NA,
          assertEvent: null,
          returnVal: undefined,
        };
      } else {
        ret[eventName][readableNodeName] = {
          order: NA,
          assertEvent: null,
          returnVal: undefined,
        };
      }
    }
  }
  return ret;
}
Test config for events that aren't negotiation related, but rather result of
a negotiation.

Returns object of the form:

    {
      responderReject: {
        // Whatever "readableIDToID" was passed in.
        grandParent: {order: NA, assertEvent: null, returnVal: blah},
        ...
        child: {order: NA, assertEvent: null, returnVal: blah},
      }
      responderGrant: {
        grandParent: {order: NA, assertEvent: null, returnVal: blah},
        ...
        child: {order: NA, assertEvent: null, returnVal: blah}
      }
      ...
    }

After this is created, a test case would configure specific event orderings
and optional assertions. Anything left with an `order` of `NA` will be
required to never be invoked (the test runner will make sure it throws if
ever invoked).