simulateDrag = (diagramText, options={}, ...extraGateEntries) => {
    let duplicate = options.duplicate || false;
    let wholeColumn = options.wholeColumn || false;

    let {circuit: beforeGrab, pts} = displayedCircuit(diagramText, ...extraGateEntries);
    let {newCircuit: afterGrab, newHand: fullHand} =
        beforeGrab.tryGrab(Hand.EMPTY.withPos(pts[0]), duplicate, wholeColumn);
    let hovers = [];
    for (let pt of pts) {
        hovers.push(afterGrab.previewDrop(fullHand.withPos(pt)));
    }
    let afterDrop = afterGrab.afterDropping(fullHand.withPos(pts[pts.length - 1]));
    let afterDropAndTidy = afterDrop.afterTidyingUp();
    return {beforeGrab, afterGrab, hovers, afterDrop, afterDropAndTidy};
}
@param {!string} diagramText
@param {undefined|!{duplicate: undefined|!boolean, wholeColumn: undefined|!boolean}} options
@param {!Array<*>} extraGateEntries
@returns {{
  beforeGrab: !DisplayedCircuit,
  afterGrab: !DisplayedCircuit,
  hovers: !Array.<!DisplayedCircuit>,
  afterDrop: !DisplayedCircuit,
  afterDropAndTidy: !DisplayedCircuit,
}}