taiko
Version:
Taiko is a Node.js library for automating Chromium based browsers
224 lines (202 loc) • 5.82 kB
JavaScript
/**
* Copyright 2018 Thoughtworks Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* This module consists of functions imported from Puppeteer(https://github.com/GoogleChrome/puppeteer)
*/
const { eventHandler } = require("../eventBus");
const { isElement } = require("../helper");
let dom;
const createdSessionListener = (client) => {
dom = client.DOM;
};
eventHandler.on("createdSession", createdSessionListener);
async function boundingBoxCenter(e) {
const box = await assertBoundingBox(e);
return {
x: box.x + box.width / 2,
y: box.y + box.height / 2,
};
}
async function boundingBoxRight(e) {
const box = await assertBoundingBox(e);
return {
x: box.x + Math.floor(box.width) - 1,
y: box.y + box.height / 2,
};
}
async function boundingBox(position, e) {
const p = position ?? "center";
switch (p) {
case "center":
return await boundingBoxCenter(e);
case "topRight":
return await boundingBoxTopRight(e);
case "topLeft":
return await boundingBoxTopLeft(e);
case "bottomRight":
return await boundingBoxBottomRight(e);
case "bottomLeft":
return await boundingBoxBottomLeft(e);
case "left":
return await boundingBoxLeft(e);
case "right":
return await boundingBoxRight(e);
default:
console.warn(
`Could not find position ${position}. Clicking at center position instead.`,
);
return await boundingBoxCenter(e);
}
}
async function boundingBoxTopLeft(e) {
const box = await assertBoundingBox(e);
return {
x: box.x,
y: box.y,
};
}
async function boundingBoxTopRight(e) {
const box = await assertBoundingBox(e);
return {
x: box.x + box.width - 1,
y: box.y,
};
}
async function boundingBoxBottomRight(e) {
const box = await assertBoundingBox(e);
return {
x: box.x + box.width - 1,
y: box.y + box.height - 1,
};
}
async function boundingBoxBottomLeft(e) {
const box = await assertBoundingBox(e);
return {
x: box.x,
y: box.y + box.height - 1,
};
}
async function boundingBoxLeft(e) {
const box = await assertBoundingBox(e);
return {
x: box.x,
y: box.y + box.height / 2,
};
}
async function boundBox(e) {
const result = await getBoxModel(e);
if (!result) {
return null;
}
const quad = result.model.border;
const x = Math.min(quad[0], quad[2], quad[4], quad[6]);
const y = Math.min(quad[1], quad[3], quad[5], quad[7]);
const width = Math.max(quad[0], quad[2], quad[4], quad[6]) - x;
const height = Math.max(quad[1], quad[3], quad[5], quad[7]) - y;
return {
x,
y,
width,
height,
};
}
async function assertBoundingBox(e) {
const boundingBox = await boundBox(e);
if (boundingBox) {
return boundingBox;
}
throw new Error("Node is either not visible or not an HTMLElement");
}
async function getBoxModel(e) {
const result = await dom.getContentQuads({
objectId: isElement(e) ? e.objectId : e,
});
return { model: { border: result.quads[0] } };
}
async function getBoundingClientRect(e) {
const result = await getBoxModel(e);
if (!result) {
return null;
}
const quad = result.model.border;
const top = Math.min(quad[1], quad[3], quad[5], quad[7]);
const bottom = Math.max(quad[1], quad[3], quad[5], quad[7]);
const left = Math.min(quad[0], quad[2], quad[4], quad[6]);
const right = Math.max(quad[0], quad[2], quad[4], quad[6]);
return { top, bottom, left, right };
}
const getPositionalDifference = async (nodeA, nodeB) => {
const r = await getBoundingClientRect(nodeA);
const v = await getBoundingClientRect(nodeB);
const topDiff = Math.abs(r.top - v.top);
const leftDiff = Math.abs(r.left - v.left);
const bottomDiff = Math.abs(r.bottom - v.bottom);
const rightDiff = Math.abs(r.right - v.right);
return topDiff + leftDiff + bottomDiff + rightDiff;
};
const calculateNewCenter = async (sourceElemobjectId, destElem) => {
const sourceBoundary = await getBoundingClientRect(sourceElemobjectId);
const newBoundary = sourceBoundary;
for (const key in destElem) {
switch (key) {
case "up":
newBoundary.top -= destElem[key];
newBoundary.bottom -= destElem[key];
break;
case "down":
newBoundary.top += destElem[key];
newBoundary.bottom += destElem[key];
break;
case "left":
newBoundary.right -= destElem[key];
newBoundary.left -= destElem[key];
break;
case "right":
newBoundary.right += destElem[key];
newBoundary.left += destElem[key];
break;
default:
throw new Error("Invalid key for destination position");
}
}
return {
y: (newBoundary.top + newBoundary.bottom) / 2,
x: (newBoundary.left + newBoundary.right) / 2,
newBoundary: newBoundary,
};
};
const setFileInputFiles = async (objectId, resolvedPath) => {
await dom.setFileInputFiles({
objectId,
files: resolvedPath,
});
};
module.exports = {
boundBox,
boundingBoxCenter,
boundingBoxRight,
boundingBox,
boundingBoxLeft,
getBoundingClientRect,
boundingBoxTopRight,
boundingBoxBottomRight,
boundingBoxBottomLeft,
boundingBoxTopLeft,
getPositionalDifference,
getBoxModel,
calculateNewCenter,
setFileInputFiles,
};