// Simulates a small pinch-zoom to provide some page scale to make the visual
// viewport able to differ from the layout viewport. The amount of zoom is
// likely to vary between browsers so tests shouldn't rely on an exact scale
// factor.
//
// Simulates two fingers, 100px apart, pulling apart vertically to 200px of
// separation.
function pinchZoomIn() {
const viewport = window.visualViewport;
const center_x = Math.floor((viewport.width * viewport.scale) / 2);
const center_y = Math.floor((viewport.height * viewport.scale) / 2);
return new test_driver.Actions()
.setContext(window)
.addPointer("finger1", "touch")
.addPointer("finger2", "touch")
.pointerMove(center_x, center_y-50, {origin: "viewport", sourceName: "finger1"})
.pointerMove(center_x, center_y+50, {origin: "viewport", sourceName: "finger2"})
.pointerDown({sourceName: "finger1"})
.pointerDown({sourceName: "finger2"})
.pointerMove(center_x, center_y-100, {origin: "viewport", sourceName: "finger1"})
.pointerMove(center_x, center_y+100, {origin: "viewport", sourceName: "finger2"})
.pointerUp({sourceName: "finger1"})
.pointerUp({sourceName: "finger2"})
.send();
}
// If scrollbars affect layout (i.e. what the CSS Overflow spec calls "classic
// scrollbars", as opposed to overlay scrollbars), return the scrollbar
// thickness in CSS pixels. Returns 0 otherwise.
function calculateScrollbarThickness() {
var container = document.createElement("div");
container.style.width = "100px";
container.style.height = "100px";
container.style.position = "absolute";
container.style.visibility = "hidden";
container.style.overflow = "auto";
document.body.appendChild(container);
var widthBefore = container.clientWidth;
var longContent = document.createElement("div");
longContent.style.height = "1000px";
container.appendChild(longContent);
var widthAfter = container.clientWidth;
container.remove();
return widthBefore - widthAfter;
}
// Puts up a widget on screen instructing the user to pinch-zoom in to the
// given scale. The widget is sized such that the given scale is achieved. The
// widget is placed at (x, y) on the page. A button on the widget is used by
// the user to let the widget know that the user has finished. If a callback is
// provided, it will be called when the user dismisses the widget.
function showPinchWidget(scale, x, y, callback) {
var border = 10;
var width = window.innerWidth / scale - border;
var height = window.innerHeight / scale - border;
var box = document.createElement("div");
box.style.width = width + "px";
box.style.height = height + "px";
// Adjust the x/y coordinates by the border width. We want the box to
// appear in a place such that if the user gets the window edges exactly on
// the half-point of the border they end up at x/y
box.style.left = x - border/2 + "px";
box.style.top = y - border/2 + "px";
box.style.position = "absolute";
box.style.backgroundColor = "coral";
box.style.border = border + "px solid blue";
box.style.borderBottom = "0";
box.style.overflow = "auto";
var oldDocumentOverflow = document.documentElement.style.overflow;
var instructions = document.createElement("p");
instructions.innerText =
"Pinch-zoom and align this box so that the left, right, and top " +
"window edges are over the border on each side. When done, click the " +
"'DONE' button above";
instructions.style.textAlign = "center";
instructions.style.fontSize = "medium";
var button = document.createElement("button");
button.innerText = "DONE";
button.style.width = "50%";
button.style.height = "20%";
button.style.fontSize = "medium";
button.style.marginLeft = "25%";
button.addEventListener("click", function() {
box.remove();
document.documentElement.style.overflow = oldDocumentOverflow;
if (callback)
callback();
});
box.appendChild(button);
box.appendChild(instructions);
document.documentElement.style.overflow = "hidden";
document.body.appendChild(box);
}
// Ends a manual test. Must be called before any async tests are started.
function skipManualTest() {
test(function() { assert_true(false); }, "Manual Test Skipped");
done();
}
var stepInstructions = [];
var testNames = [];
var stepFunctions = [];
var steps;
var curStep = 0;
// Adds a manual test step to the test. A test will add a series of steps,
// along with instructions. Once all the tests steps are added, the test can
// be run by continually running the nextStep() function. All manual test steps
// must be added before calling nextStep.
//
// |func| A function to be executed at the given step. This function can include
// testharness assertions if |testName| is provided. If this is the last
// step, the |done()| function (used for manual testharness.js tests)
// will be called after |func| is executed.
// |testName| If provided, the |func| will be wrapped in a testharness.js
// async_test with this name. If null, |func| will be executed as a
// free function.
// |instructions| The text to display to the user. Note, these are shown after
// step is executed so these should be instructions to setup the
// checks in the next step.
function addManualTestStep(func, testName, instructions) {
stepFunctions.push(func);
testNames.push(testName);
stepInstructions.push(instructions);
}
// Runs the next step of the test. This must be called only after all test steps
// have been added using |addManualTestStep|.
//
// |callbackFunc| If provided, will be called with a single argument being the
// instruction string for the current step. Use this to update
// any necessary UI.
function nextStep(callbackFunc) {
if (curStep == 0)
_startManualTest();
if (typeof(callbackFunc) === 'function')
callbackFunc(stepInstructions[curStep]);
steps[curStep]();
curStep++;
}
function _startManualTest() {
steps = [];
for (let i = 0; i < stepFunctions.length; ++i) {
var stepFunc = stepFunctions[i];
var testName = testNames[i];
if (testName) {
steps.push(async_test(testName).step_func(function() {
stepFunctions[i]();
this.done();
if (i == stepFunctions.length - 1)
done();
}));
} else {
steps.push(function() {
stepFunctions[i]();
if (i == stepFunctions.length - 1)
done();
});
}
}
}