1731 lines
56 KiB
JavaScript
1731 lines
56 KiB
JavaScript
|
|
window.UIHelper = class UIHelper {
|
|
static isIOSFamily()
|
|
{
|
|
return testRunner.isIOSFamily;
|
|
}
|
|
|
|
static isWebKit2()
|
|
{
|
|
return testRunner.isWebKit2;
|
|
}
|
|
|
|
static doubleClickAt(x, y)
|
|
{
|
|
eventSender.mouseMoveTo(x, y);
|
|
eventSender.mouseDown();
|
|
eventSender.mouseUp();
|
|
eventSender.mouseDown();
|
|
eventSender.mouseUp();
|
|
}
|
|
|
|
static doubleClickAtMouseDown(x1, y1)
|
|
{
|
|
eventSender.mouseMoveTo(x1, y1);
|
|
eventSender.mouseDown();
|
|
eventSender.mouseUp();
|
|
eventSender.mouseDown();
|
|
}
|
|
|
|
static mouseUp()
|
|
{
|
|
eventSender.mouseUp();
|
|
}
|
|
|
|
static doubleClickAtThenDragTo(x1, y1, x2, y2)
|
|
{
|
|
eventSender.mouseMoveTo(x1, y1);
|
|
eventSender.mouseDown();
|
|
eventSender.mouseUp();
|
|
eventSender.mouseDown();
|
|
eventSender.mouseMoveTo(x2, y2);
|
|
eventSender.mouseUp();
|
|
}
|
|
|
|
static dragMouseAcrossElement(element)
|
|
{
|
|
const x1 = element.offsetLeft + element.offsetWidth;
|
|
const x2 = element.offsetLeft + element.offsetWidth * .75;
|
|
const x3 = element.offsetLeft + element.offsetWidth / 2;
|
|
const x4 = element.offsetLeft + element.offsetWidth / 4;
|
|
const x5 = element.offsetLeft;
|
|
const y = element.offsetTop + element.offsetHeight / 2;
|
|
eventSender.mouseMoveTo(x1, y);
|
|
eventSender.mouseMoveTo(x2, y);
|
|
eventSender.mouseMoveTo(x3, y);
|
|
eventSender.mouseMoveTo(x4, y);
|
|
eventSender.mouseMoveTo(x5, y);
|
|
}
|
|
|
|
static doubleClickElementMouseDown(element1)
|
|
{
|
|
const x1 = element1.offsetLeft + element1.offsetWidth / 2;
|
|
const y1 = element1.offsetTop + element1.offsetHeight / 2;
|
|
return UIHelper.doubleClickAtMouseDown(x1, y1);
|
|
}
|
|
|
|
static async moveMouseAndWaitForFrame(x, y)
|
|
{
|
|
eventSender.mouseMoveTo(x, y);
|
|
await UIHelper.animationFrame();
|
|
}
|
|
|
|
static async mouseWheelScrollAt(x, y, beginX, beginY, deltaX, deltaY)
|
|
{
|
|
if (beginX === undefined)
|
|
beginX = 0;
|
|
if (beginY === undefined)
|
|
beginY = -1;
|
|
|
|
if (deltaX === undefined)
|
|
deltaX = 0;
|
|
if (deltaY === undefined)
|
|
deltaY = -10;
|
|
|
|
eventSender.monitorWheelEvents();
|
|
eventSender.mouseMoveTo(x, y);
|
|
eventSender.mouseScrollByWithWheelAndMomentumPhases(beginX, beginY, "began", "none");
|
|
eventSender.mouseScrollByWithWheelAndMomentumPhases(deltaX, deltaY, "changed", "none");
|
|
eventSender.mouseScrollByWithWheelAndMomentumPhases(0, 0, "ended", "none");
|
|
return new Promise(resolve => {
|
|
eventSender.callAfterScrollingCompletes(() => {
|
|
requestAnimationFrame(resolve);
|
|
});
|
|
});
|
|
}
|
|
|
|
static async mouseWheelMayBeginAt(x, y)
|
|
{
|
|
eventSender.mouseMoveTo(x, y);
|
|
eventSender.mouseScrollByWithWheelAndMomentumPhases(x, y, "maybegin", "none");
|
|
await UIHelper.animationFrame();
|
|
}
|
|
|
|
static async mouseWheelCancelAt(x, y)
|
|
{
|
|
eventSender.mouseMoveTo(x, y);
|
|
eventSender.mouseScrollByWithWheelAndMomentumPhases(x, y, "cancelled", "none");
|
|
await UIHelper.animationFrame();
|
|
}
|
|
|
|
static async waitForScrollCompletion()
|
|
{
|
|
return new Promise(resolve => {
|
|
eventSender.callAfterScrollingCompletes(() => {
|
|
requestAnimationFrame(resolve);
|
|
});
|
|
});
|
|
}
|
|
|
|
static async animationFrame()
|
|
{
|
|
return new Promise(requestAnimationFrame);
|
|
}
|
|
|
|
static async renderingUpdate()
|
|
{
|
|
await UIHelper.animationFrame();
|
|
await UIHelper.delayFor(0);
|
|
}
|
|
|
|
static async waitForCondition(conditionFunc)
|
|
{
|
|
while (!conditionFunc()) {
|
|
await UIHelper.animationFrame();
|
|
}
|
|
}
|
|
|
|
static sendEventStream(eventStream)
|
|
{
|
|
const eventStreamAsString = JSON.stringify(eventStream);
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`
|
|
(function() {
|
|
uiController.sendEventStream(\`${eventStreamAsString}\`, () => {
|
|
uiController.uiScriptComplete();
|
|
});
|
|
})();
|
|
`, resolve);
|
|
});
|
|
}
|
|
|
|
static tapAt(x, y, modifiers=[])
|
|
{
|
|
console.assert(this.isIOSFamily());
|
|
|
|
if (!this.isWebKit2()) {
|
|
console.assert(!modifiers || !modifiers.length);
|
|
eventSender.addTouchPoint(x, y);
|
|
eventSender.touchStart();
|
|
eventSender.releaseTouchPoint(0);
|
|
eventSender.touchEnd();
|
|
return Promise.resolve();
|
|
}
|
|
|
|
return new Promise((resolve) => {
|
|
testRunner.runUIScript(`
|
|
uiController.singleTapAtPointWithModifiers(${x}, ${y}, ${JSON.stringify(modifiers)}, function() {
|
|
uiController.uiScriptComplete();
|
|
});`, resolve);
|
|
});
|
|
}
|
|
|
|
static tapElement(element, delay = 0)
|
|
{
|
|
const x = element.offsetLeft + (element.offsetWidth / 2);
|
|
const y = element.offsetTop + (element.offsetHeight / 2);
|
|
this.tapAt(x, y);
|
|
}
|
|
|
|
static doubleTapElement(element, delay = 0)
|
|
{
|
|
const x = element.offsetLeft + (element.offsetWidth / 2);
|
|
const y = element.offsetTop + (element.offsetHeight / 2);
|
|
this.doubleTapAt(x, y, delay);
|
|
}
|
|
|
|
static doubleTapAt(x, y, delay = 0)
|
|
{
|
|
console.assert(this.isIOSFamily());
|
|
|
|
if (!this.isWebKit2()) {
|
|
eventSender.addTouchPoint(x, y);
|
|
eventSender.touchStart();
|
|
eventSender.releaseTouchPoint(0);
|
|
eventSender.touchEnd();
|
|
eventSender.addTouchPoint(x, y);
|
|
eventSender.touchStart();
|
|
eventSender.releaseTouchPoint(0);
|
|
eventSender.touchEnd();
|
|
return Promise.resolve();
|
|
}
|
|
|
|
return new Promise((resolve) => {
|
|
testRunner.runUIScript(`
|
|
uiController.doubleTapAtPoint(${x}, ${y}, ${delay}, function() {
|
|
uiController.uiScriptComplete();
|
|
});`, resolve);
|
|
});
|
|
}
|
|
|
|
static humanSpeedDoubleTapAt(x, y)
|
|
{
|
|
console.assert(this.isIOSFamily());
|
|
|
|
if (!this.isWebKit2()) {
|
|
// FIXME: Add a sleep in here.
|
|
eventSender.addTouchPoint(x, y);
|
|
eventSender.touchStart();
|
|
eventSender.releaseTouchPoint(0);
|
|
eventSender.touchEnd();
|
|
eventSender.addTouchPoint(x, y);
|
|
eventSender.touchStart();
|
|
eventSender.releaseTouchPoint(0);
|
|
eventSender.touchEnd();
|
|
return Promise.resolve();
|
|
}
|
|
|
|
return UIHelper.doubleTapAt(x, y, 0.12);
|
|
}
|
|
|
|
static humanSpeedZoomByDoubleTappingAt(x, y)
|
|
{
|
|
console.assert(this.isIOSFamily());
|
|
|
|
if (!this.isWebKit2()) {
|
|
// FIXME: Add a sleep in here.
|
|
eventSender.addTouchPoint(x, y);
|
|
eventSender.touchStart();
|
|
eventSender.releaseTouchPoint(0);
|
|
eventSender.touchEnd();
|
|
eventSender.addTouchPoint(x, y);
|
|
eventSender.touchStart();
|
|
eventSender.releaseTouchPoint(0);
|
|
eventSender.touchEnd();
|
|
return Promise.resolve();
|
|
}
|
|
|
|
return new Promise(async (resolve) => {
|
|
testRunner.runUIScript(`
|
|
uiController.didEndZoomingCallback = () => {
|
|
uiController.didEndZoomingCallback = null;
|
|
uiController.uiScriptComplete(uiController.zoomScale);
|
|
};
|
|
uiController.doubleTapAtPoint(${x}, ${y}, 0.12, () => { });`, resolve);
|
|
});
|
|
}
|
|
|
|
static zoomByDoubleTappingAt(x, y)
|
|
{
|
|
console.assert(this.isIOSFamily());
|
|
|
|
if (!this.isWebKit2()) {
|
|
eventSender.addTouchPoint(x, y);
|
|
eventSender.touchStart();
|
|
eventSender.releaseTouchPoint(0);
|
|
eventSender.touchEnd();
|
|
eventSender.addTouchPoint(x, y);
|
|
eventSender.touchStart();
|
|
eventSender.releaseTouchPoint(0);
|
|
eventSender.touchEnd();
|
|
return Promise.resolve();
|
|
}
|
|
|
|
return new Promise((resolve) => {
|
|
testRunner.runUIScript(`
|
|
uiController.didEndZoomingCallback = () => {
|
|
uiController.didEndZoomingCallback = null;
|
|
uiController.uiScriptComplete(uiController.zoomScale);
|
|
};
|
|
uiController.doubleTapAtPoint(${x}, ${y}, 0, () => { });`, resolve);
|
|
});
|
|
}
|
|
|
|
static activateAt(x, y, modifiers=[])
|
|
{
|
|
if (!this.isWebKit2() || !this.isIOSFamily()) {
|
|
eventSender.mouseMoveTo(x, y);
|
|
eventSender.mouseDown(0, modifiers);
|
|
eventSender.mouseUp(0, modifiers);
|
|
return Promise.resolve();
|
|
}
|
|
|
|
return new Promise((resolve) => {
|
|
testRunner.runUIScript(`
|
|
uiController.singleTapAtPointWithModifiers(${x}, ${y}, ${JSON.stringify(modifiers)}, function() {
|
|
uiController.uiScriptComplete();
|
|
});`, resolve);
|
|
});
|
|
}
|
|
|
|
static activateElement(element, modifiers=[])
|
|
{
|
|
const x = element.offsetLeft + element.offsetWidth / 2;
|
|
const y = element.offsetTop + element.offsetHeight / 2;
|
|
return UIHelper.activateAt(x, y, modifiers);
|
|
}
|
|
|
|
static async doubleActivateAt(x, y)
|
|
{
|
|
if (this.isIOSFamily())
|
|
await UIHelper.doubleTapAt(x, y);
|
|
else
|
|
await UIHelper.doubleClickAt(x, y);
|
|
}
|
|
|
|
static async doubleActivateAtSelectionStart()
|
|
{
|
|
const rects = window.getSelection().getRangeAt(0).getClientRects();
|
|
const x = rects[0].left;
|
|
const y = rects[0].top;
|
|
if (this.isIOSFamily()) {
|
|
await UIHelper.activateAndWaitForInputSessionAt(x, y);
|
|
await UIHelper.doubleTapAt(x, y);
|
|
// This is only here to deal with async/sync copy/paste calls, so
|
|
// once <rdar://problem/16207002> is resolved, should be able to remove for faster tests.
|
|
await new Promise(resolve => testRunner.runUIScript("uiController.uiScriptComplete()", resolve));
|
|
} else
|
|
await UIHelper.doubleClickAt(x, y);
|
|
}
|
|
|
|
static async selectWordByDoubleTapOrClick(element, relativeX = 5, relativeY = 5)
|
|
{
|
|
const boundingRect = element.getBoundingClientRect();
|
|
const x = boundingRect.x + relativeX;
|
|
const y = boundingRect.y + relativeY;
|
|
if (this.isIOSFamily()) {
|
|
await UIHelper.activateAndWaitForInputSessionAt(x, y);
|
|
await UIHelper.doubleTapAt(x, y);
|
|
// This is only here to deal with async/sync copy/paste calls, so
|
|
// once <rdar://problem/16207002> is resolved, should be able to remove for faster tests.
|
|
await new Promise(resolve => testRunner.runUIScript("uiController.uiScriptComplete()", resolve));
|
|
} else {
|
|
await UIHelper.doubleClickAt(x, y);
|
|
}
|
|
}
|
|
|
|
static keyDown(key, modifiers=[])
|
|
{
|
|
if (!this.isWebKit2() || !this.isIOSFamily()) {
|
|
eventSender.keyDown(key, modifiers);
|
|
return Promise.resolve();
|
|
}
|
|
|
|
return new Promise((resolve) => {
|
|
testRunner.runUIScript(`uiController.keyDown("${key}", ${JSON.stringify(modifiers)});`, resolve);
|
|
});
|
|
}
|
|
|
|
static toggleCapsLock()
|
|
{
|
|
return new Promise((resolve) => {
|
|
testRunner.runUIScript(`uiController.toggleCapsLock(() => uiController.uiScriptComplete());`, resolve);
|
|
});
|
|
}
|
|
|
|
static keyboardIsAutomaticallyShifted()
|
|
{
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`uiController.keyboardIsAutomaticallyShifted`, result => resolve(result === "true"));
|
|
});
|
|
}
|
|
|
|
static isAnimatingDragCancel()
|
|
{
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`uiController.isAnimatingDragCancel`, result => resolve(result === "true"));
|
|
});
|
|
}
|
|
|
|
static ensurePresentationUpdate()
|
|
{
|
|
if (!this.isWebKit2()) {
|
|
testRunner.display();
|
|
return Promise.resolve();
|
|
}
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`
|
|
uiController.doAfterPresentationUpdate(function() {
|
|
uiController.uiScriptComplete();
|
|
});`, resolve);
|
|
});
|
|
}
|
|
|
|
static ensureStablePresentationUpdate()
|
|
{
|
|
if (!this.isWebKit2()) {
|
|
testRunner.display();
|
|
return Promise.resolve();
|
|
}
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`
|
|
uiController.doAfterNextStablePresentationUpdate(function() {
|
|
uiController.uiScriptComplete();
|
|
});`, resolve);
|
|
});
|
|
}
|
|
|
|
static ensurePositionInformationUpdateForElement(element)
|
|
{
|
|
const boundingRect = element.getBoundingClientRect();
|
|
const x = boundingRect.x + 5;
|
|
const y = boundingRect.y + 5;
|
|
|
|
if (!this.isWebKit2()) {
|
|
testRunner.display();
|
|
return Promise.resolve();
|
|
}
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`
|
|
uiController.ensurePositionInformationIsUpToDateAt(${x}, ${y}, function () {
|
|
uiController.uiScriptComplete();
|
|
});`, resolve);
|
|
});
|
|
}
|
|
|
|
static delayFor(ms)
|
|
{
|
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
}
|
|
|
|
static scrollTo(x, y, unconstrained)
|
|
{
|
|
if (!this.isWebKit2()) {
|
|
window.scrollTo(x, y);
|
|
return Promise.resolve();
|
|
}
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`
|
|
(function() {
|
|
uiController.didEndScrollingCallback = function() {
|
|
uiController.uiScriptComplete();
|
|
}
|
|
uiController.scrollToOffset(${x}, ${y}, { unconstrained: ${unconstrained} });
|
|
})()`, resolve);
|
|
});
|
|
}
|
|
|
|
static immediateScrollTo(x, y, unconstrained)
|
|
{
|
|
if (!this.isWebKit2()) {
|
|
window.scrollTo(x, y);
|
|
return Promise.resolve();
|
|
}
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`
|
|
uiController.immediateScrollToOffset(${x}, ${y}, { unconstrained: ${unconstrained} });`, resolve);
|
|
});
|
|
}
|
|
|
|
static immediateUnstableScrollTo(x, y, unconstrained)
|
|
{
|
|
if (!this.isWebKit2()) {
|
|
window.scrollTo(x, y);
|
|
return Promise.resolve();
|
|
}
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`
|
|
uiController.stableStateOverride = false;
|
|
uiController.immediateScrollToOffset(${x}, ${y}, { unconstrained: ${unconstrained} });`, resolve);
|
|
});
|
|
}
|
|
|
|
static immediateScrollElementAtContentPointToOffset(x, y, scrollX, scrollY, scrollUpdatesDisabled = false)
|
|
{
|
|
if (!this.isWebKit2())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`
|
|
uiController.scrollUpdatesDisabled = ${scrollUpdatesDisabled};
|
|
uiController.immediateScrollElementAtContentPointToOffset(${x}, ${y}, ${scrollX}, ${scrollY});`, resolve);
|
|
});
|
|
}
|
|
|
|
static ensureVisibleContentRectUpdate()
|
|
{
|
|
if (!this.isWebKit2())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => {
|
|
const visibleContentRectUpdateScript = "uiController.doAfterVisibleContentRectUpdate(() => uiController.uiScriptComplete())";
|
|
testRunner.runUIScript(visibleContentRectUpdateScript, resolve);
|
|
});
|
|
}
|
|
|
|
static longPressAndGetContextMenuContentAt(x, y)
|
|
{
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`
|
|
(function() {
|
|
uiController.didShowContextMenuCallback = function() {
|
|
uiController.uiScriptComplete(JSON.stringify(uiController.contentsOfUserInterfaceItem('contextMenu')));
|
|
};
|
|
uiController.longPressAtPoint(${x}, ${y}, function() { });
|
|
})();`, result => resolve(JSON.parse(result)));
|
|
});
|
|
}
|
|
|
|
static activateAndWaitForInputSessionAt(x, y)
|
|
{
|
|
if (!this.isWebKit2() || !this.isIOSFamily())
|
|
return this.activateAt(x, y);
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`
|
|
(function() {
|
|
function clearCallbacksAndScriptComplete() {
|
|
uiController.didShowContextMenuCallback = null;
|
|
uiController.didShowKeyboardCallback = null;
|
|
uiController.willPresentPopoverCallback = null;
|
|
uiController.uiScriptComplete();
|
|
}
|
|
uiController.didShowContextMenuCallback = clearCallbacksAndScriptComplete;
|
|
uiController.didShowKeyboardCallback = clearCallbacksAndScriptComplete;
|
|
uiController.willPresentPopoverCallback = clearCallbacksAndScriptComplete;
|
|
uiController.singleTapAtPoint(${x}, ${y}, function() { });
|
|
})()`, resolve);
|
|
});
|
|
}
|
|
|
|
static waitForInputSessionToDismiss()
|
|
{
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`
|
|
(function() {
|
|
if (!uiController.isShowingKeyboard && !uiController.isShowingContextMenu && !uiController.isShowingPopover) {
|
|
uiController.uiScriptComplete();
|
|
return;
|
|
}
|
|
|
|
function clearCallbacksAndScriptComplete() {
|
|
uiController.didHideKeyboardCallback = null;
|
|
uiController.didDismissPopoverCallback = null;
|
|
uiController.didDismissContextMenuCallback = null;
|
|
uiController.uiScriptComplete();
|
|
}
|
|
|
|
uiController.didHideKeyboardCallback = clearCallbacksAndScriptComplete;
|
|
uiController.didDismissPopoverCallback = clearCallbacksAndScriptComplete;
|
|
uiController.didDismissContextMenuCallback = clearCallbacksAndScriptComplete;
|
|
})()`, resolve);
|
|
});
|
|
}
|
|
|
|
static activateElementAndWaitForInputSession(element)
|
|
{
|
|
const x = element.offsetLeft + element.offsetWidth / 2;
|
|
const y = element.offsetTop + element.offsetHeight / 2;
|
|
return this.activateAndWaitForInputSessionAt(x, y);
|
|
}
|
|
|
|
static activateFormControl(element)
|
|
{
|
|
if (!this.isWebKit2() || !this.isIOSFamily())
|
|
return this.activateElement(element);
|
|
|
|
const x = element.offsetLeft + element.offsetWidth / 2;
|
|
const y = element.offsetTop + element.offsetHeight / 2;
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`
|
|
(function() {
|
|
uiController.didStartFormControlInteractionCallback = function() {
|
|
uiController.uiScriptComplete();
|
|
};
|
|
uiController.singleTapAtPoint(${x}, ${y}, function() { });
|
|
})()`, resolve);
|
|
});
|
|
}
|
|
|
|
static dismissFormAccessoryView()
|
|
{
|
|
if (!this.isWebKit2() || !this.isIOSFamily())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`
|
|
(function() {
|
|
uiController.dismissFormAccessoryView();
|
|
uiController.uiScriptComplete();
|
|
})()`, resolve);
|
|
});
|
|
}
|
|
|
|
static isShowingKeyboard()
|
|
{
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript("uiController.isShowingKeyboard", result => resolve(result === "true"));
|
|
});
|
|
}
|
|
|
|
static isShowingPopover()
|
|
{
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript("uiController.isShowingPopover", result => resolve(result === "true"));
|
|
});
|
|
}
|
|
|
|
static hasInputSession()
|
|
{
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript("uiController.hasInputSession", result => resolve(result === "true"));
|
|
});
|
|
}
|
|
|
|
static isPresentingModally()
|
|
{
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript("uiController.isPresentingModally", result => resolve(result === "true"));
|
|
});
|
|
}
|
|
|
|
static deactivateFormControl(element)
|
|
{
|
|
if (!this.isWebKit2() || !this.isIOSFamily()) {
|
|
element.blur();
|
|
return Promise.resolve();
|
|
}
|
|
|
|
return new Promise(async resolve => {
|
|
element.blur();
|
|
while (await this.isPresentingModally())
|
|
continue;
|
|
while (await this.isShowingKeyboard())
|
|
continue;
|
|
resolve();
|
|
});
|
|
}
|
|
|
|
static waitForPopoverToPresent()
|
|
{
|
|
if (!this.isWebKit2() || !this.isIOSFamily())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`
|
|
(function() {
|
|
if (uiController.isShowingPopover)
|
|
uiController.uiScriptComplete();
|
|
else
|
|
uiController.willPresentPopoverCallback = () => uiController.uiScriptComplete();
|
|
})()`, resolve);
|
|
});
|
|
}
|
|
|
|
static waitForPopoverToDismiss()
|
|
{
|
|
if (!this.isWebKit2() || !this.isIOSFamily())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`
|
|
(function() {
|
|
if (uiController.isShowingPopover)
|
|
uiController.didDismissPopoverCallback = () => uiController.uiScriptComplete();
|
|
else
|
|
uiController.uiScriptComplete();
|
|
})()`, resolve);
|
|
});
|
|
}
|
|
|
|
static waitForContextMenuToShow()
|
|
{
|
|
if (!this.isWebKit2() || !this.isIOSFamily())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`
|
|
(function() {
|
|
if (!uiController.isShowingContextMenu)
|
|
uiController.didShowContextMenuCallback = () => uiController.uiScriptComplete();
|
|
else
|
|
uiController.uiScriptComplete();
|
|
})()`, resolve);
|
|
});
|
|
}
|
|
|
|
static waitForContextMenuToHide()
|
|
{
|
|
if (!this.isWebKit2() || !this.isIOSFamily())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`
|
|
(function() {
|
|
if (uiController.isShowingContextMenu)
|
|
uiController.didDismissContextMenuCallback = () => uiController.uiScriptComplete();
|
|
else
|
|
uiController.uiScriptComplete();
|
|
})()`, resolve);
|
|
});
|
|
}
|
|
|
|
static waitForKeyboardToHide()
|
|
{
|
|
if (!this.isWebKit2() || !this.isIOSFamily())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`
|
|
(function() {
|
|
if (uiController.isShowingKeyboard)
|
|
uiController.didHideKeyboardCallback = () => uiController.uiScriptComplete();
|
|
else
|
|
uiController.uiScriptComplete();
|
|
})()`, resolve);
|
|
});
|
|
}
|
|
|
|
static getUICaretRect()
|
|
{
|
|
if (!this.isWebKit2() || !this.isIOSFamily())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`(function() {
|
|
uiController.doAfterNextStablePresentationUpdate(function() {
|
|
uiController.uiScriptComplete(JSON.stringify(uiController.textSelectionCaretRect));
|
|
});
|
|
})()`, jsonString => {
|
|
resolve(JSON.parse(jsonString));
|
|
});
|
|
});
|
|
}
|
|
|
|
static getUISelectionRects()
|
|
{
|
|
if (!this.isWebKit2() || !this.isIOSFamily())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`(function() {
|
|
uiController.doAfterNextStablePresentationUpdate(function() {
|
|
uiController.uiScriptComplete(JSON.stringify(uiController.textSelectionRangeRects));
|
|
});
|
|
})()`, jsonString => {
|
|
resolve(JSON.parse(jsonString));
|
|
});
|
|
});
|
|
}
|
|
|
|
static getUICaretViewRect()
|
|
{
|
|
if (!this.isWebKit2() || !this.isIOSFamily())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`(function() {
|
|
uiController.doAfterNextStablePresentationUpdate(function() {
|
|
uiController.uiScriptComplete(JSON.stringify(uiController.selectionCaretViewRect));
|
|
});
|
|
})()`, jsonString => {
|
|
resolve(JSON.parse(jsonString));
|
|
});
|
|
});
|
|
}
|
|
|
|
static getUISelectionViewRects()
|
|
{
|
|
if (!this.isWebKit2() || !this.isIOSFamily())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`(function() {
|
|
uiController.doAfterNextStablePresentationUpdate(function() {
|
|
uiController.uiScriptComplete(JSON.stringify(uiController.selectionRangeViewRects));
|
|
});
|
|
})()`, jsonString => {
|
|
resolve(JSON.parse(jsonString));
|
|
});
|
|
});
|
|
}
|
|
|
|
static getSelectionStartGrabberViewRect()
|
|
{
|
|
if (!this.isWebKit2() || !this.isIOSFamily())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`(function() {
|
|
uiController.doAfterNextStablePresentationUpdate(function() {
|
|
uiController.uiScriptComplete(JSON.stringify(uiController.selectionStartGrabberViewRect));
|
|
});
|
|
})()`, jsonString => {
|
|
resolve(JSON.parse(jsonString));
|
|
});
|
|
});
|
|
}
|
|
|
|
static getSelectionEndGrabberViewRect()
|
|
{
|
|
if (!this.isWebKit2() || !this.isIOSFamily())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`(function() {
|
|
uiController.doAfterNextStablePresentationUpdate(function() {
|
|
uiController.uiScriptComplete(JSON.stringify(uiController.selectionEndGrabberViewRect));
|
|
});
|
|
})()`, jsonString => {
|
|
resolve(JSON.parse(jsonString));
|
|
});
|
|
});
|
|
}
|
|
|
|
static selectionCaretBackgroundColor()
|
|
{
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript("uiController.uiScriptComplete(uiController.selectionCaretBackgroundColor)", resolve);
|
|
});
|
|
}
|
|
|
|
static tapHighlightViewRect()
|
|
{
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript("JSON.stringify(uiController.tapHighlightViewRect)", jsonString => {
|
|
resolve(JSON.parse(jsonString));
|
|
});
|
|
});
|
|
}
|
|
|
|
static replaceTextAtRange(text, location, length) {
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`(() => {
|
|
uiController.replaceTextAtRange("${text}", ${location}, ${length});
|
|
uiController.uiScriptComplete();
|
|
})()`, resolve);
|
|
});
|
|
}
|
|
|
|
static wait(promise)
|
|
{
|
|
testRunner.waitUntilDone();
|
|
if (window.finishJSTest)
|
|
window.jsTestIsAsync = true;
|
|
|
|
let finish = () => {
|
|
if (window.finishJSTest)
|
|
finishJSTest();
|
|
else
|
|
testRunner.notifyDone();
|
|
}
|
|
|
|
return promise.then(finish, finish);
|
|
}
|
|
|
|
static withUserGesture(callback)
|
|
{
|
|
internals.withUserGesture(callback);
|
|
}
|
|
|
|
static selectFormAccessoryPickerRow(rowIndex)
|
|
{
|
|
const selectRowScript = `uiController.selectFormAccessoryPickerRow(${rowIndex})`;
|
|
return new Promise(resolve => testRunner.runUIScript(selectRowScript, resolve));
|
|
}
|
|
|
|
static selectFormAccessoryHasCheckedItemAtRow(rowIndex)
|
|
{
|
|
return new Promise(resolve => testRunner.runUIScript(`uiController.selectFormAccessoryHasCheckedItemAtRow(${rowIndex})`, result => {
|
|
resolve(result === "true");
|
|
}));
|
|
}
|
|
|
|
static selectFormPopoverTitle()
|
|
{
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`(() => {
|
|
uiController.uiScriptComplete(uiController.selectFormPopoverTitle);
|
|
})()`, resolve);
|
|
});
|
|
}
|
|
|
|
static setSelectedColorForColorPicker(red, green, blue)
|
|
{
|
|
const selectColorScript = `uiController.setSelectedColorForColorPicker(${red}, ${green}, ${blue})`;
|
|
return new Promise(resolve => testRunner.runUIScript(selectColorScript, resolve));
|
|
}
|
|
|
|
static enterText(text)
|
|
{
|
|
const escapedText = text.replace(/`/g, "\\`");
|
|
const enterTextScript = `(() => uiController.enterText(\`${escapedText}\`))()`;
|
|
return new Promise(resolve => testRunner.runUIScript(enterTextScript, resolve));
|
|
}
|
|
|
|
static setTimePickerValue(hours, minutes)
|
|
{
|
|
const setValueScript = `(() => uiController.setTimePickerValue(${hours}, ${minutes}))()`;
|
|
return new Promise(resolve => testRunner.runUIScript(setValueScript, resolve));
|
|
}
|
|
|
|
static timerPickerValues()
|
|
{
|
|
if (!this.isIOSFamily())
|
|
return Promise.resolve();
|
|
|
|
const uiScript = "JSON.stringify([uiController.timePickerValueHour, uiController.timePickerValueMinute])";
|
|
return new Promise(resolve => testRunner.runUIScript(uiScript, result => {
|
|
const [hour, minute] = JSON.parse(result)
|
|
resolve({ hour: hour, minute: minute });
|
|
}));
|
|
}
|
|
|
|
static textContentType()
|
|
{
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`(() => {
|
|
uiController.uiScriptComplete(uiController.textContentType);
|
|
})()`, resolve);
|
|
});
|
|
}
|
|
|
|
static formInputLabel()
|
|
{
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`(() => {
|
|
uiController.uiScriptComplete(uiController.formInputLabel);
|
|
})()`, resolve);
|
|
});
|
|
}
|
|
|
|
static dismissFilePicker()
|
|
{
|
|
if (!this.isWebKit2() || !this.isIOSFamily())
|
|
return Promise.resolve();
|
|
|
|
const script = `uiController.dismissFilePicker(() => {
|
|
uiController.uiScriptComplete();
|
|
})`;
|
|
return new Promise(resolve => testRunner.runUIScript(script, resolve));
|
|
}
|
|
|
|
static filePickerAcceptedTypeIdentifiers()
|
|
{
|
|
if (!this.isWebKit2() || !this.isIOSFamily())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`(() => {
|
|
uiController.uiScriptComplete(JSON.stringify(uiController.filePickerAcceptedTypeIdentifiers));
|
|
})()`, jsonString => {
|
|
resolve(JSON.parse(jsonString));
|
|
});
|
|
});
|
|
}
|
|
|
|
static activateDataListSuggestion(index) {
|
|
const script = `uiController.activateDataListSuggestion(${index}, () => {
|
|
uiController.uiScriptComplete("");
|
|
});`;
|
|
return new Promise(resolve => testRunner.runUIScript(script, resolve));
|
|
}
|
|
|
|
static isShowingDataListSuggestions()
|
|
{
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`(() => {
|
|
uiController.uiScriptComplete(uiController.isShowingDataListSuggestions);
|
|
})()`, result => resolve(result === "true"));
|
|
});
|
|
}
|
|
|
|
static isShowingDateTimePicker()
|
|
{
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`(() => {
|
|
uiController.uiScriptComplete(uiController.isShowingDateTimePicker);
|
|
})()`, result => resolve(result === "true"));
|
|
});
|
|
}
|
|
|
|
static dateTimePickerValue()
|
|
{
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`(() => {
|
|
uiController.uiScriptComplete(uiController.dateTimePickerValue);
|
|
})()`, valueAsString => resolve(parseFloat(valueAsString)));
|
|
});
|
|
}
|
|
|
|
static chooseDateTimePickerValue()
|
|
{
|
|
return new Promise((resolve) => {
|
|
testRunner.runUIScript(`
|
|
uiController.chooseDateTimePickerValue();
|
|
uiController.uiScriptComplete();
|
|
`, resolve);
|
|
});
|
|
}
|
|
|
|
static zoomScale()
|
|
{
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`(() => {
|
|
uiController.uiScriptComplete(uiController.zoomScale);
|
|
})()`, scaleAsString => resolve(parseFloat(scaleAsString)));
|
|
});
|
|
}
|
|
|
|
static zoomToScale(scale)
|
|
{
|
|
const uiScript = `uiController.zoomToScale(${scale}, () => uiController.uiScriptComplete(uiController.zoomScale))`;
|
|
return new Promise(resolve => testRunner.runUIScript(uiScript, resolve));
|
|
}
|
|
|
|
static immediateZoomToScale(scale)
|
|
{
|
|
const uiScript = `uiController.immediateZoomToScale(${scale})`;
|
|
return new Promise(resolve => testRunner.runUIScript(uiScript, resolve));
|
|
}
|
|
|
|
static typeCharacter(characterString)
|
|
{
|
|
if (!this.isWebKit2() || !this.isIOSFamily()) {
|
|
eventSender.keyDown(characterString);
|
|
return;
|
|
}
|
|
|
|
const escapedString = characterString.replace(/\\/g, "\\\\").replace(/`/g, "\\`");
|
|
const uiScript = `uiController.typeCharacterUsingHardwareKeyboard(\`${escapedString}\`, () => uiController.uiScriptComplete())`;
|
|
return new Promise(resolve => testRunner.runUIScript(uiScript, resolve));
|
|
}
|
|
|
|
static applyAutocorrection(newText, oldText)
|
|
{
|
|
if (!this.isWebKit2())
|
|
return;
|
|
|
|
const [escapedNewText, escapedOldText] = [newText.replace(/`/g, "\\`"), oldText.replace(/`/g, "\\`")];
|
|
const uiScript = `uiController.applyAutocorrection(\`${escapedNewText}\`, \`${escapedOldText}\`, () => uiController.uiScriptComplete())`;
|
|
return new Promise(resolve => testRunner.runUIScript(uiScript, resolve));
|
|
}
|
|
|
|
static inputViewBounds()
|
|
{
|
|
if (!this.isWebKit2() || !this.isIOSFamily())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`(() => {
|
|
uiController.uiScriptComplete(JSON.stringify(uiController.inputViewBounds));
|
|
})()`, jsonString => {
|
|
resolve(JSON.parse(jsonString));
|
|
});
|
|
});
|
|
}
|
|
|
|
static calendarType()
|
|
{
|
|
if (!this.isWebKit2())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`(() => {
|
|
uiController.doAfterNextStablePresentationUpdate(() => {
|
|
uiController.uiScriptComplete(JSON.stringify(uiController.calendarType));
|
|
})
|
|
})()`, jsonString => {
|
|
resolve(JSON.parse(jsonString));
|
|
});
|
|
});
|
|
}
|
|
|
|
static setDefaultCalendarType(calendarIdentifier, localeIdentifier)
|
|
{
|
|
if (!this.isWebKit2())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => testRunner.runUIScript(`uiController.setDefaultCalendarType('${calendarIdentifier}', '${localeIdentifier}')`, resolve));
|
|
|
|
}
|
|
|
|
static setViewScale(scale)
|
|
{
|
|
if (!this.isWebKit2())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => testRunner.runUIScript(`uiController.setViewScale(${scale})`, resolve));
|
|
}
|
|
|
|
static resignFirstResponder()
|
|
{
|
|
if (!this.isWebKit2())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => testRunner.runUIScript(`uiController.resignFirstResponder()`, resolve));
|
|
}
|
|
|
|
static becomeFirstResponder()
|
|
{
|
|
if (!this.isWebKit2())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => testRunner.runUIScript(`uiController.becomeFirstResponder()`, resolve));
|
|
}
|
|
|
|
static removeViewFromWindow()
|
|
{
|
|
if (!this.isWebKit2())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => testRunner.runUIScript(`uiController.removeViewFromWindow()`, resolve));
|
|
}
|
|
|
|
static addViewToWindow()
|
|
{
|
|
if (!this.isWebKit2())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => testRunner.runUIScript(`uiController.addViewToWindow()`, resolve));
|
|
}
|
|
|
|
static minimumZoomScale()
|
|
{
|
|
if (!this.isWebKit2())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`(() => {
|
|
uiController.uiScriptComplete(uiController.minimumZoomScale);
|
|
})()`, scaleAsString => resolve(parseFloat(scaleAsString)))
|
|
});
|
|
}
|
|
|
|
static stylusTapAt(x, y, modifiers=[])
|
|
{
|
|
if (!this.isWebKit2())
|
|
return Promise.resolve();
|
|
|
|
return new Promise((resolve) => {
|
|
testRunner.runUIScript(`
|
|
uiController.stylusTapAtPointWithModifiers(${x}, ${y}, 2, 1, 0.5, ${JSON.stringify(modifiers)}, function() {
|
|
uiController.uiScriptComplete();
|
|
});`, resolve);
|
|
});
|
|
}
|
|
|
|
static attachmentInfo(attachmentIdentifier)
|
|
{
|
|
if (!this.isWebKit2())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`(() => {
|
|
uiController.uiScriptComplete(JSON.stringify(uiController.attachmentInfo('${attachmentIdentifier}')));
|
|
})()`, jsonString => {
|
|
resolve(JSON.parse(jsonString));
|
|
})
|
|
});
|
|
}
|
|
|
|
static insertAttachmentForFilePath(path, contentType)
|
|
{
|
|
if (!this.isWebKit2())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`
|
|
uiController.insertAttachmentForFilePath('${path}', '${contentType}', function() {
|
|
uiController.uiScriptComplete();
|
|
});`, resolve);
|
|
});
|
|
}
|
|
|
|
static setMinimumEffectiveWidth(effectiveWidth)
|
|
{
|
|
if (!this.isWebKit2())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => testRunner.runUIScript(`uiController.setMinimumEffectiveWidth(${effectiveWidth})`, resolve));
|
|
}
|
|
|
|
static setAllowsViewportShrinkToFit(allows)
|
|
{
|
|
if (!this.isWebKit2())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => testRunner.runUIScript(`uiController.setAllowsViewportShrinkToFit(${allows})`, resolve));
|
|
}
|
|
|
|
static setKeyboardInputModeIdentifier(identifier)
|
|
{
|
|
if (!this.isWebKit2())
|
|
return Promise.resolve();
|
|
|
|
const escapedIdentifier = identifier.replace(/`/g, "\\`");
|
|
return new Promise(resolve => testRunner.runUIScript(`uiController.setKeyboardInputModeIdentifier(\`${escapedIdentifier}\`)`, resolve));
|
|
}
|
|
|
|
static contentOffset()
|
|
{
|
|
if (!this.isIOSFamily())
|
|
return Promise.resolve();
|
|
|
|
const uiScript = "JSON.stringify([uiController.contentOffsetX, uiController.contentOffsetY])";
|
|
return new Promise(resolve => testRunner.runUIScript(uiScript, result => {
|
|
const [offsetX, offsetY] = JSON.parse(result)
|
|
resolve({ x: offsetX, y: offsetY });
|
|
}));
|
|
}
|
|
|
|
static undoAndRedoLabels()
|
|
{
|
|
if (!this.isWebKit2())
|
|
return Promise.resolve();
|
|
|
|
const script = "JSON.stringify([uiController.lastUndoLabel, uiController.firstRedoLabel])";
|
|
return new Promise(resolve => testRunner.runUIScript(script, result => resolve(JSON.parse(result))));
|
|
}
|
|
|
|
static waitForMenuToShow()
|
|
{
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`
|
|
(function() {
|
|
if (!uiController.isShowingMenu)
|
|
uiController.didShowMenuCallback = () => uiController.uiScriptComplete();
|
|
else
|
|
uiController.uiScriptComplete();
|
|
})()`, resolve);
|
|
});
|
|
}
|
|
|
|
static waitForMenuToHide()
|
|
{
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`
|
|
(function() {
|
|
if (uiController.isShowingMenu)
|
|
uiController.didHideMenuCallback = () => uiController.uiScriptComplete();
|
|
else
|
|
uiController.uiScriptComplete();
|
|
})()`, resolve);
|
|
});
|
|
}
|
|
|
|
static isShowingMenu()
|
|
{
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`uiController.isShowingMenu`, result => resolve(result === "true"));
|
|
});
|
|
}
|
|
|
|
static isDismissingMenu()
|
|
{
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`uiController.isDismissingMenu`, result => resolve(result === "true"));
|
|
});
|
|
}
|
|
|
|
static menuRect()
|
|
{
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript("JSON.stringify(uiController.menuRect)", result => resolve(JSON.parse(result)));
|
|
});
|
|
}
|
|
|
|
static setHardwareKeyboardAttached(attached)
|
|
{
|
|
return new Promise(resolve => testRunner.runUIScript(`uiController.setHardwareKeyboardAttached(${attached ? "true" : "false"})`, resolve));
|
|
}
|
|
|
|
static rectForMenuAction(action)
|
|
{
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`
|
|
(() => {
|
|
const rect = uiController.rectForMenuAction("${action}");
|
|
uiController.uiScriptComplete(rect ? JSON.stringify(rect) : "");
|
|
})();
|
|
`, stringResult => {
|
|
resolve(stringResult.length ? JSON.parse(stringResult) : null);
|
|
});
|
|
});
|
|
}
|
|
|
|
static chooseMenuAction(action)
|
|
{
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`
|
|
(() => {
|
|
uiController.chooseMenuAction("${action}", () => {
|
|
uiController.uiScriptComplete();
|
|
});
|
|
})();
|
|
`, resolve);
|
|
});
|
|
}
|
|
|
|
static waitForEvent(target, eventName)
|
|
{
|
|
return new Promise(resolve => target.addEventListener(eventName, resolve, { once: true }));
|
|
}
|
|
|
|
static callFunctionAndWaitForEvent(functionToCall, target, eventName)
|
|
{
|
|
return new Promise(async resolve => {
|
|
let event;
|
|
await Promise.all([
|
|
new Promise((eventListenerResolve) => {
|
|
target.addEventListener(eventName, (e) => {
|
|
event = e;
|
|
eventListenerResolve();
|
|
}, {once: true});
|
|
}),
|
|
new Promise(async functionResolve => {
|
|
await functionToCall();
|
|
functionResolve();
|
|
})
|
|
]);
|
|
resolve(event);
|
|
});
|
|
}
|
|
|
|
static callFunctionAndWaitForScrollToFinish(functionToCall, ...theArguments)
|
|
{
|
|
return UIHelper.callFunctionAndWaitForTargetScrollToFinish(window, functionToCall, theArguments)
|
|
}
|
|
|
|
static callFunctionAndWaitForTargetScrollToFinish(scrollTarget, functionToCall, ...theArguments)
|
|
{
|
|
return new Promise((resolved) => {
|
|
function scrollDidFinish() {
|
|
scrollTarget.removeEventListener("scroll", handleScroll, true);
|
|
resolved();
|
|
}
|
|
|
|
let lastScrollTimerId = 0; // When the timer with this id fires then the page has finished scrolling.
|
|
function handleScroll() {
|
|
if (lastScrollTimerId) {
|
|
window.clearTimeout(lastScrollTimerId);
|
|
lastScrollTimerId = 0;
|
|
}
|
|
lastScrollTimerId = window.setTimeout(scrollDidFinish, 300); // Over 250ms to give some room for error.
|
|
}
|
|
scrollTarget.addEventListener("scroll", handleScroll, true);
|
|
|
|
functionToCall.apply(this, theArguments);
|
|
});
|
|
}
|
|
|
|
static waitForTargetScrollAnimationToSettle(scrollTarget)
|
|
{
|
|
return new Promise((resolved) => {
|
|
let lastObservedScrollPosition = [scrollTarget.scrollLeft, scrollTarget.scrollTop];
|
|
let frameOfLastChange = 0;
|
|
let totalFrames = 0;
|
|
|
|
function animationFrame() {
|
|
if (lastObservedScrollPosition[0] != scrollTarget.scrollLeft ||
|
|
lastObservedScrollPosition[1] != scrollTarget.scrollTop) {
|
|
lastObservedScrollPosition = [scrollTarget.scrollLeft, scrollTarget.scrollTop];
|
|
frameOfLastChange = totalFrames;
|
|
}
|
|
|
|
// If we have gone 20 frames without changing, resolve. If we have gone 500, then time out.
|
|
// This matches the amount of frames used in the WPT scroll animation helper.
|
|
if (totalFrames - frameOfLastChange >= 20 || totalFrames > 500)
|
|
resolved();
|
|
|
|
totalFrames++;
|
|
requestAnimationFrame(animationFrame);
|
|
}
|
|
|
|
requestAnimationFrame(animationFrame);
|
|
});
|
|
}
|
|
|
|
static rotateDevice(orientationName, animatedResize = false)
|
|
{
|
|
if (!this.isWebKit2() || !this.isIOSFamily())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`(() => {
|
|
uiController.${animatedResize ? "simulateRotationLikeSafari" : "simulateRotation"}("${orientationName}", function() {
|
|
uiController.doAfterVisibleContentRectUpdate(() => uiController.uiScriptComplete());
|
|
});
|
|
})()`, resolve);
|
|
});
|
|
}
|
|
|
|
static getScrollingTree()
|
|
{
|
|
if (!this.isWebKit2() || !this.isIOSFamily())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`(() => {
|
|
return uiController.scrollingTreeAsText;
|
|
})()`, resolve);
|
|
});
|
|
}
|
|
|
|
static getUIViewTree()
|
|
{
|
|
if (!this.isWebKit2() || !this.isIOSFamily())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`(() => {
|
|
return uiController.uiViewTreeAsText;
|
|
})()`, resolve);
|
|
});
|
|
}
|
|
|
|
static dragFromPointToPoint(fromX, fromY, toX, toY, duration)
|
|
{
|
|
if (!this.isWebKit2() || !this.isIOSFamily()) {
|
|
eventSender.mouseMoveTo(fromX, fromY);
|
|
eventSender.mouseDown();
|
|
eventSender.leapForward(duration * 1000);
|
|
eventSender.mouseMoveTo(toX, toY);
|
|
eventSender.mouseUp();
|
|
return Promise.resolve();
|
|
}
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`(() => {
|
|
uiController.dragFromPointToPoint(${fromX}, ${fromY}, ${toX}, ${toY}, ${duration}, () => {
|
|
uiController.uiScriptComplete();
|
|
});
|
|
})();`, resolve);
|
|
});
|
|
}
|
|
|
|
static setWindowIsKey(isKey)
|
|
{
|
|
const script = `uiController.windowIsKey = ${isKey}`;
|
|
return new Promise(resolve => testRunner.runUIScript(script, resolve));
|
|
}
|
|
|
|
static windowIsKey()
|
|
{
|
|
const script = "uiController.uiScriptComplete(uiController.windowIsKey)";
|
|
return new Promise(resolve => testRunner.runUIScript(script, (result) => {
|
|
resolve(result === "true");
|
|
}));
|
|
}
|
|
|
|
static waitForDoubleTapDelay()
|
|
{
|
|
const uiScript = `uiController.doAfterDoubleTapDelay(() => uiController.uiScriptComplete(""))`;
|
|
return new Promise(resolve => testRunner.runUIScript(uiScript, resolve));
|
|
}
|
|
|
|
static async waitForSelectionToAppear() {
|
|
while (true) {
|
|
let selectionRects = await this.getUISelectionViewRects();
|
|
if (selectionRects.length > 0)
|
|
return selectionRects;
|
|
}
|
|
}
|
|
|
|
static async waitForSelectionToDisappear() {
|
|
while (true) {
|
|
if (!(await this.getUISelectionViewRects()).length)
|
|
break;
|
|
}
|
|
}
|
|
|
|
static async copyText(text) {
|
|
const copyTextScript = `uiController.copyText(\`${text.replace(/`/g, "\\`")}\`)`;
|
|
return new Promise(resolve => testRunner.runUIScript(copyTextScript, resolve));
|
|
}
|
|
|
|
static async paste() {
|
|
return new Promise(resolve => testRunner.runUIScript(`uiController.paste()`, resolve));
|
|
}
|
|
|
|
static async setContinuousSpellCheckingEnabled(enabled) {
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`uiController.setContinuousSpellCheckingEnabled(${enabled})`, resolve);
|
|
});
|
|
}
|
|
|
|
static async longPressElement(element)
|
|
{
|
|
return this.longPressAtPoint(element.offsetLeft + element.offsetWidth / 2, element.offsetTop + element.offsetHeight / 2);
|
|
}
|
|
|
|
static async longPressAtPoint(x, y)
|
|
{
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`
|
|
(function() {
|
|
uiController.longPressAtPoint(${x}, ${y}, function() {
|
|
uiController.uiScriptComplete();
|
|
});
|
|
})();`, resolve);
|
|
});
|
|
}
|
|
|
|
static async setSpellCheckerResults(results)
|
|
{
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`(() => {
|
|
uiController.setSpellCheckerResults(${JSON.stringify(results)});
|
|
uiController.uiScriptComplete();
|
|
})()`, resolve);
|
|
});
|
|
}
|
|
|
|
static async activateElementAfterInstallingTapGestureOnWindow(element)
|
|
{
|
|
if (!this.isWebKit2() || !this.isIOSFamily())
|
|
return activateElement(element);
|
|
|
|
const x = element.offsetLeft + element.offsetWidth / 2;
|
|
const y = element.offsetTop + element.offsetHeight / 2;
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`
|
|
(function() {
|
|
let progress = 0;
|
|
function incrementProgress() {
|
|
if (++progress == 2)
|
|
uiController.uiScriptComplete();
|
|
}
|
|
uiController.installTapGestureOnWindow(incrementProgress);
|
|
uiController.singleTapAtPoint(${x}, ${y}, incrementProgress);
|
|
})();`, resolve);
|
|
});
|
|
}
|
|
|
|
static mayContainEditableElementsInRect(x, y, width, height)
|
|
{
|
|
if (!this.isWebKit2() || !this.isIOSFamily())
|
|
return Promise.resolve(false);
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`
|
|
(function() {
|
|
uiController.doAfterPresentationUpdate(function() {
|
|
uiController.uiScriptComplete(uiController.mayContainEditableElementsInRect(${x}, ${y}, ${width}, ${height}));
|
|
})
|
|
})();`, result => resolve(result === "true"));
|
|
});
|
|
}
|
|
|
|
static moveToNextByKeyboardAccessoryBar()
|
|
{
|
|
return new Promise((resolve) => {
|
|
testRunner.runUIScript(`
|
|
uiController.keyboardAccessoryBarNext();
|
|
uiController.uiScriptComplete();
|
|
`, resolve);
|
|
});
|
|
}
|
|
|
|
static moveToPrevByKeyboardAccessoryBar()
|
|
{
|
|
return new Promise((resolve) => {
|
|
testRunner.runUIScript(`
|
|
uiController.keyboardAccessoryBarPrevious();
|
|
uiController.uiScriptComplete();
|
|
`, resolve);
|
|
});
|
|
}
|
|
|
|
static waitForContactPickerToShow()
|
|
{
|
|
if (!this.isWebKit2())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`
|
|
(function() {
|
|
if (!uiController.isShowingContactPicker)
|
|
uiController.didShowContactPickerCallback = () => uiController.uiScriptComplete();
|
|
else
|
|
uiController.uiScriptComplete();
|
|
})()`, resolve);
|
|
});
|
|
}
|
|
|
|
static waitForContactPickerToHide()
|
|
{
|
|
if (!this.isWebKit2())
|
|
return Promise.resolve();
|
|
|
|
return new Promise(resolve => {
|
|
testRunner.runUIScript(`
|
|
(function() {
|
|
if (uiController.isShowingContactPicker)
|
|
uiController.didHideContactPickerCallback = () => uiController.uiScriptComplete();
|
|
else
|
|
uiController.uiScriptComplete();
|
|
})()`, resolve);
|
|
});
|
|
}
|
|
|
|
static dismissContactPickerWithContacts(contacts)
|
|
{
|
|
const script = `(() => uiController.dismissContactPickerWithContacts(${JSON.stringify(contacts)}))()`;
|
|
return new Promise(resolve => testRunner.runUIScript(script, resolve));
|
|
}
|
|
|
|
static addChromeInputField()
|
|
{
|
|
return new Promise(resolve => testRunner.addChromeInputField(resolve));
|
|
}
|
|
|
|
static removeChromeInputField()
|
|
{
|
|
return new Promise(resolve => testRunner.removeChromeInputField(resolve));
|
|
}
|
|
|
|
static setTextInChromeInputField(text)
|
|
{
|
|
return new Promise(resolve => testRunner.setTextInChromeInputField(text, resolve));
|
|
}
|
|
|
|
static selectChromeInputField()
|
|
{
|
|
return new Promise(resolve => testRunner.selectChromeInputField(resolve));
|
|
}
|
|
|
|
static getSelectedTextInChromeInputField()
|
|
{
|
|
return new Promise(resolve => testRunner.getSelectedTextInChromeInputField(resolve));
|
|
}
|
|
}
|
|
|
|
UIHelper.EventStreamBuilder = class {
|
|
constructor()
|
|
{
|
|
// FIXME: This could support additional customization options, such as interpolation, timestep, and different
|
|
// digitizer indices in the future. For now, just make it simpler to string together sequences of pan gestures.
|
|
this._reset();
|
|
}
|
|
|
|
_reset() {
|
|
this.events = [];
|
|
this.currentTimeOffset = 0;
|
|
this.currentX = 0;
|
|
this.currentY = 0;
|
|
}
|
|
|
|
begin(x, y) {
|
|
console.assert(this.currentTimeOffset === 0);
|
|
this.events.push({
|
|
interpolate : "linear",
|
|
timestep : 0.016,
|
|
coordinateSpace : "content",
|
|
startEvent : {
|
|
inputType : "hand",
|
|
timeOffset : this.currentTimeOffset,
|
|
touches : [{ inputType : "finger", phase : "began", id : 1, x : x, y : y, pressure : 0 }]
|
|
},
|
|
endEvent : {
|
|
inputType : "hand",
|
|
timeOffset : this.currentTimeOffset,
|
|
touches : [{ inputType : "finger", phase : "began", id : 1, x : x, y : y, pressure : 0 }]
|
|
}
|
|
});
|
|
this.currentX = x;
|
|
this.currentY = y;
|
|
return this;
|
|
}
|
|
|
|
wait(duration) {
|
|
this.currentTimeOffset += duration;
|
|
return this;
|
|
}
|
|
|
|
move(x, y, duration = 0) {
|
|
const previousTimeOffset = this.currentTimeOffset;
|
|
this.currentTimeOffset += duration;
|
|
this.events.push({
|
|
interpolate : "linear",
|
|
timestep : 0.016,
|
|
coordinateSpace : "content",
|
|
startEvent : {
|
|
inputType : "hand",
|
|
timeOffset : previousTimeOffset,
|
|
touches : [{ inputType : "finger", phase : "moved", id : 1, x : this.currentX, y : this.currentY, pressure : 0 }]
|
|
},
|
|
endEvent : {
|
|
inputType : "hand",
|
|
timeOffset : this.currentTimeOffset,
|
|
touches : [{ inputType : "finger", phase : "moved", id : 1, x : x, y : y, pressure : 0 }]
|
|
}
|
|
});
|
|
this.currentX = x;
|
|
this.currentY = y;
|
|
return this;
|
|
}
|
|
|
|
end() {
|
|
this.events.push({
|
|
interpolate : "linear",
|
|
timestep : 0.016,
|
|
coordinateSpace : "content",
|
|
startEvent : {
|
|
inputType : "hand",
|
|
timeOffset : this.currentTimeOffset,
|
|
touches : [{ inputType : "finger", phase : "ended", id : 1, x : this.currentX, y : this.currentY, pressure : 0 }]
|
|
},
|
|
endEvent : {
|
|
inputType : "hand",
|
|
timeOffset : this.currentTimeOffset,
|
|
touches : [{ inputType : "finger", phase : "ended", id : 1, x : this.currentX, y : this.currentY, pressure : 0 }]
|
|
}
|
|
});
|
|
return this;
|
|
}
|
|
|
|
takeResult() {
|
|
const events = this.events;
|
|
this._reset();
|
|
return { "events": events };
|
|
}
|
|
}
|