| |
| 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 statelessMouseWheelScrollAt(x, y, deltaX, deltaY) |
| { |
| eventSender.monitorWheelEvents(); |
| eventSender.mouseMoveTo(x, y); |
| eventSender.mouseScrollBy(deltaX, deltaY); |
| 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 mouseWheelSequence(eventStream, { waitForCompletion = true } = {}) |
| { |
| if (waitForCompletion) |
| eventSender.monitorWheelEvents(); |
| const eventStreamAsString = JSON.stringify(eventStream); |
| await new Promise(resolve => { |
| testRunner.runUIScript(` |
| (function() { |
| uiController.sendEventStream(\`${eventStreamAsString}\`, () => { |
| uiController.uiScriptComplete(); |
| }); |
| })(); |
| `, resolve); |
| }); |
| |
| if (waitForCompletion) |
| await UIHelper.waitForScrollCompletion(); |
| } |
| |
| 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 rawKeyDown(key, modifiers=[]) |
| { |
| if (!this.isWebKit2() || !this.isIOSFamily()) { |
| eventSender.rawKeyDown(key, modifiers); |
| return Promise.resolve(); |
| } |
| |
| return new Promise((resolve) => { |
| testRunner.runUIScript(`uiController.rawKeyDown("${key}", ${JSON.stringify(modifiers)});`, resolve); |
| }); |
| } |
| |
| static rawKeyUp(key, modifiers=[]) |
| { |
| if (!this.isWebKit2() || !this.isIOSFamily()) { |
| eventSender.rawKeyUp(key, modifiers); |
| return Promise.resolve(); |
| } |
| |
| return new Promise((resolve) => { |
| testRunner.runUIScript(`uiController.rawKeyUp("${key}", ${JSON.stringify(modifiers)});`, resolve); |
| }); |
| } |
| |
| 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 midPointOfRect(rect) { |
| return { x: rect.left + (rect.width / 2), y: rect.top + (rect.height / 2) }; |
| } |
| |
| 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 setScrollViewKeyboardAvoidanceEnabled(enabled) |
| { |
| if (!this.isWebKit2()) |
| return Promise.resolve(); |
| |
| return new Promise(resolve => testRunner.runUIScript(`uiController.setScrollViewKeyboardAvoidanceEnabled(${enabled})`, 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 }; |
| } |
| } |