Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@qawolf/web

Package Overview
Dependencies
Maintainers
2
Versions
40
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@qawolf/web - npm Package Compare versions

Comparing version 0.5.7 to 0.5.8

lib/crawl.d.ts

2

lib/element.d.ts

@@ -9,1 +9,3 @@ import { ElementDescriptor } from "@qawolf/types";

export declare const getDescriptor: (element: HTMLElement, dataAttribute: string | null) => ElementDescriptor;
export declare const isClickable: (element: HTMLElement, computedStyle: CSSStyleDeclaration) => boolean;
export declare const isVisible: (element: HTMLElement, computedStyle?: CSSStyleDeclaration | undefined) => boolean;

@@ -133,2 +133,13 @@ "use strict";

};
exports.isClickable = (element, computedStyle) => {
const clickable = computedStyle.cursor === "pointer";
return clickable && exports.isVisible(element, computedStyle);
};
exports.isVisible = (element, computedStyle) => {
if (element.offsetWidth <= 0 || element.offsetHeight <= 0)
return false;
if (computedStyle && computedStyle.visibility === "hidden")
return false;
return true;
};
//# sourceMappingURL=element.js.map

2

lib/find.d.ts

@@ -7,8 +7,8 @@ import { Action, Locator } from "@qawolf/types";

};
export declare const isVisible: (element: HTMLElement) => boolean;
export declare const queryActionElements: (action: Action) => HTMLElement[];
export declare const queryDataElements: ({ action, dataAttribute, dataValue }: QueryByDataArgs) => HTMLElement[];
export declare const queryVisibleElements: (selector: string) => HTMLElement[];
export declare const findClickableAncestor: (element: HTMLElement, dataAttribute: string) => HTMLElement;
export declare const findElement: ({ action, dataAttribute, target, timeoutMs, value }: Locator) => Promise<HTMLElement | null>;
export declare const hasText: (text: string, timeoutMs: number) => Promise<boolean>;
export {};

@@ -12,8 +12,6 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
const element_1 = require("./element");
const match_1 = require("./match");
const wait_1 = require("./wait");
const xpath_1 = require("./xpath");
exports.isVisible = (element) => {
return !!(element.offsetWidth && element.offsetHeight);
};
exports.queryActionElements = (action) => {

@@ -35,3 +33,3 @@ const selector = action === "type" ? "input,select,textarea,[contenteditable='true']" : "*";

for (let i = 0; i < elements.length; i++) {
if (exports.isVisible(elements[i])) {
if (element_1.isVisible(elements[i])) {
visibleElements.push(elements[i]);

@@ -42,2 +40,19 @@ }

};
exports.findClickableAncestor = (element, dataAttribute) => {
let ancestor = element;
console.log("find clickable ancestor for", xpath_1.getXpath(element));
while (ancestor.parentElement) {
const dataValue = element_1.getDataValue(ancestor, dataAttribute);
if (dataValue) {
console.log(`found clickable ancestor with ${dataAttribute}="${dataValue}"`, xpath_1.getXpath(ancestor));
return ancestor;
}
if (!element_1.isClickable(ancestor.parentElement, window.getComputedStyle(ancestor.parentElement))) {
console.log("found clickable ancestor", xpath_1.getXpath(ancestor));
return ancestor;
}
ancestor = ancestor.parentElement;
}
return ancestor;
};
exports.findElement = ({ action, dataAttribute, target, timeoutMs, value }) => __awaiter(void 0, void 0, void 0, function* () {

@@ -60,4 +75,4 @@ if (dataAttribute && target.dataValue) {

return xpath_1.findElementByXpath(target.xpath);
console.log("waiting for top strong match", target);
const strongMatch = yield wait_1.waitFor(() => {
console.log("waiting for top strong match", target);
const elements = exports.queryActionElements(action);

@@ -64,0 +79,0 @@ return match_1.topMatch({

@@ -19,3 +19,3 @@ import * as element from "./element";

}[], countPresentKeys: (descriptor: import("@qawolf/types").ElementDescriptor) => number, isNil: (value?: any) => boolean;
declare const sleep: (milliseconds: number) => Promise<void>, waitFor: <T>(valueFn: () => T | null, timeoutMs: number, sleepMs?: number) => Promise<T | null>, waitUntil: (booleanFn: () => boolean, timeoutMs: number, sleepMs?: number) => Promise<void>;
declare const sleep: (milliseconds: number) => Promise<void>, waitFor: <T>(valueFn: () => T | null, timeoutMs: number, sleepMs?: number) => Promise<T | null>, waitUntil: (booleanFn: () => boolean | Promise<boolean>, timeoutMs: number, sleepMs?: number) => Promise<void>;
export { compareArrays, compareDescriptorKey, compareDescriptors, countPresentKeys, isKeyEvent, isNil, sleep, waitFor, waitUntil };

@@ -22,0 +22,0 @@ declare const webExports: {

@@ -23,4 +23,4 @@ import { ElementDescriptor } from "@qawolf/types";

export declare const compareArrays: (base?: string[] | null | undefined, compare?: string[] | null | undefined) => number;
export declare const compareDescriptorKey: (key: "dataValue" | "title" | "alt" | "ariaLabel" | "classList" | "href" | "iconContent" | "id" | "inputType" | "isContentEditable" | "labels" | "name" | "parentText" | "placeholder" | "src" | "tagName" | "innerText" | "xpath", targetValue: DescriptorValue, compareValue: DescriptorValue) => {
key: "dataValue" | "title" | "alt" | "ariaLabel" | "classList" | "href" | "iconContent" | "id" | "inputType" | "isContentEditable" | "labels" | "name" | "parentText" | "placeholder" | "src" | "tagName" | "innerText" | "xpath";
export declare const compareDescriptorKey: (key: "alt" | "ariaLabel" | "classList" | "dataValue" | "href" | "iconContent" | "id" | "inputType" | "isContentEditable" | "labels" | "name" | "parentText" | "placeholder" | "src" | "tagName" | "innerText" | "title" | "xpath", targetValue: DescriptorValue, compareValue: DescriptorValue) => {
key: "alt" | "ariaLabel" | "classList" | "dataValue" | "href" | "iconContent" | "id" | "inputType" | "isContentEditable" | "labels" | "name" | "parentText" | "placeholder" | "src" | "tagName" | "innerText" | "title" | "xpath";
percent: number;

@@ -27,0 +27,0 @@ };

@@ -187,2 +187,14 @@ var qawolf = (function (exports) {

};
var isClickable = function (element, computedStyle) {
// assume it is clickable if the cursor is a pointer
var clickable = computedStyle.cursor === "pointer";
return clickable && isVisible(element, computedStyle);
};
var isVisible = function (element, computedStyle) {
if (element.offsetWidth <= 0 || element.offsetHeight <= 0)
return false;
if (computedStyle && computedStyle.visibility === "hidden")
return false;
return true;
};

@@ -197,3 +209,5 @@ var element = /*#__PURE__*/Object.freeze({

getTextContent: getTextContent,
getDescriptor: getDescriptor
getDescriptor: getDescriptor,
isClickable: isClickable,
isVisible: isVisible
});

@@ -429,11 +443,13 @@

case 1:
if (!(Date.now() - startTime < timeoutMs)) return [3 /*break*/, 3];
conditionMet = booleanFn();
if (!(Date.now() - startTime < timeoutMs)) return [3 /*break*/, 4];
return [4 /*yield*/, booleanFn()];
case 2:
conditionMet = _a.sent();
if (conditionMet)
return [2 /*return*/];
return [4 /*yield*/, sleep(sleepMs)];
case 2:
case 3:
_a.sent();
return [3 /*break*/, 1];
case 3: throw new Error("waitUntil: waited " + timeoutMs + " milliseconds but condition never met");
case 4: throw new Error("waitUntil: waited " + timeoutMs + " milliseconds but condition never met");
}

@@ -451,5 +467,2 @@ });

var isVisible = function (element) {
return !!(element.offsetWidth && element.offsetHeight);
};
var queryActionElements = function (action) {

@@ -472,2 +485,4 @@ var selector = action === "type" ? "input,select,textarea,[contenteditable='true']" : "*";

for (var i = 0; i < elements.length; i++) {
// we do not pass computedStyle because doing
// that for every element would be very expensive
if (isVisible(elements[i])) {

@@ -479,2 +494,24 @@ visibleElements.push(elements[i]);

};
var findClickableAncestor = function (element, dataAttribute) {
/**
* Crawl up until we reach the top "clickable" ancestor
*/
var ancestor = element;
console.log("find clickable ancestor for", getXpath(element));
while (ancestor.parentElement) {
// short-circuit when we encounter a data value
var dataValue = getDataValue(ancestor, dataAttribute);
if (dataValue) {
console.log("found clickable ancestor with " + dataAttribute + "=\"" + dataValue + "\"", getXpath(ancestor));
return ancestor;
}
// short-circuit when parent is not clickable
if (!isClickable(ancestor.parentElement, window.getComputedStyle(ancestor.parentElement))) {
console.log("found clickable ancestor", getXpath(ancestor));
return ancestor;
}
ancestor = ancestor.parentElement;
}
return ancestor;
};
var findElement = function (_a) {

@@ -504,4 +541,4 @@ var action = _a.action, dataAttribute = _a.dataAttribute, target = _a.target, timeoutMs = _a.timeoutMs, value = _a.value;

return [2 /*return*/, findElementByXpath(target.xpath)];
console.log("waiting for top strong match", target);
return [4 /*yield*/, waitFor(function () {
console.log("waiting for top strong match", target);
var elements = queryActionElements(action);

@@ -554,6 +591,6 @@ return topMatch({

__proto__: null,
isVisible: isVisible,
queryActionElements: queryActionElements,
queryDataElements: queryDataElements,
queryVisibleElements: queryVisibleElements,
findClickableAncestor: findClickableAncestor,
findElement: findElement,

@@ -594,8 +631,19 @@ hasText: hasText

var _this = this;
this.recordEvent("click", function (event) { return ({
isTrusted: event.isTrusted,
name: "click",
target: getDescriptor(event.target, _this._dataAttribute),
time: Date.now()
}); });
this.recordEvent("click", function (event) {
// findClickableAncestor chooses the ancestor if it has a data-attribute
// which is very likely the target we want to click on.
// If there is not a data-attribute on any of the clickable ancestors
// it will take the top most clickable ancestor.
// The ancestor is likely a better target than the descendant.
// Ex. when you click on the i (button > i) or rect (a > svg > rect)
// chances are the ancestor (button, a) is a better target to find.
// XXX if anyone runs into issues with this behavior we can allow disabling it from a flag.
var target = findClickableAncestor(event.target, _this._dataAttribute);
return {
isTrusted: event.isTrusted,
name: "click",
target: getDescriptor(target, _this._dataAttribute),
time: Date.now()
};
});
this.recordEvent("input", function (event) {

@@ -602,0 +650,0 @@ var element = event.target;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const element_1 = require("./element");
const find_1 = require("./find");
class Recorder {

@@ -31,8 +32,11 @@ constructor(dataAttribute, sendEvent) {

recordEvents() {
this.recordEvent("click", event => ({
isTrusted: event.isTrusted,
name: "click",
target: element_1.getDescriptor(event.target, this._dataAttribute),
time: Date.now()
}));
this.recordEvent("click", event => {
const target = find_1.findClickableAncestor(event.target, this._dataAttribute);
return {
isTrusted: event.isTrusted,
name: "click",
target: element_1.getDescriptor(target, this._dataAttribute),
time: Date.now()
};
});
this.recordEvent("input", event => {

@@ -39,0 +43,0 @@ const element = event.target;

export declare const sleep: (milliseconds: number) => Promise<void>;
export declare const waitFor: <T>(valueFn: () => T | null, timeoutMs: number, sleepMs?: number) => Promise<T | null>;
export declare const waitUntil: (booleanFn: () => boolean, timeoutMs: number, sleepMs?: number) => Promise<void>;
export declare const waitUntil: (booleanFn: () => boolean | Promise<boolean>, timeoutMs: number, sleepMs?: number) => Promise<void>;

@@ -28,3 +28,3 @@ "use strict";

while (Date.now() - startTime < timeoutMs) {
const conditionMet = booleanFn();
const conditionMet = yield booleanFn();
if (conditionMet)

@@ -31,0 +31,0 @@ return;

{
"name": "@qawolf/web",
"description": "qawolf web library",
"version": "0.5.7",
"version": "0.5.8",
"license": "BSD-3.0",

@@ -33,3 +33,3 @@ "main": "./lib/index.js",

},
"gitHead": "e9e0ec59744286f261d36a8f82d7059a8a69cd3c"
"gitHead": "7f90e207884baeb510f318b5489226a554bc076a"
}

@@ -166,1 +166,21 @@ import { ElementDescriptor } from "@qawolf/types";

};
export const isClickable = (
element: HTMLElement,
computedStyle: CSSStyleDeclaration
) => {
// assume it is clickable if the cursor is a pointer
const clickable = computedStyle.cursor === "pointer";
return clickable && isVisible(element, computedStyle);
};
export const isVisible = (
element: HTMLElement,
computedStyle?: CSSStyleDeclaration
): boolean => {
if (element.offsetWidth <= 0 || element.offsetHeight <= 0) return false;
if (computedStyle && computedStyle.visibility === "hidden") return false;
return true;
};
import { Action, Locator } from "@qawolf/types";
import { getDataValue, isClickable, isVisible } from "./element";
import { topMatch } from "./match";
import { waitFor } from "./wait";
import { findElementByXpath } from "./xpath";
import { findElementByXpath, getXpath } from "./xpath";

@@ -12,6 +13,2 @@ type QueryByDataArgs = {

export const isVisible = (element: HTMLElement): boolean => {
return !!(element.offsetWidth && element.offsetHeight);
};
export const queryActionElements = (action: Action): HTMLElement[] => {

@@ -44,2 +41,4 @@ const selector =

for (let i = 0; i < elements.length; i++) {
// we do not pass computedStyle because doing
// that for every element would be very expensive
if (isVisible(elements[i] as HTMLElement)) {

@@ -53,2 +52,40 @@ visibleElements.push(elements[i] as HTMLElement);

export const findClickableAncestor = (
element: HTMLElement,
dataAttribute: string
): HTMLElement => {
/**
* Crawl up until we reach the top "clickable" ancestor
*/
let ancestor = element;
console.log("find clickable ancestor for", getXpath(element));
while (ancestor.parentElement) {
// short-circuit when we encounter a data value
const dataValue = getDataValue(ancestor, dataAttribute);
if (dataValue) {
console.log(
`found clickable ancestor with ${dataAttribute}="${dataValue}"`,
getXpath(ancestor)
);
return ancestor;
}
// short-circuit when parent is not clickable
if (
!isClickable(
ancestor.parentElement,
window.getComputedStyle(ancestor.parentElement)
)
) {
console.log("found clickable ancestor", getXpath(ancestor));
return ancestor;
}
ancestor = ancestor.parentElement;
}
return ancestor;
};
export const findElement = async ({

@@ -84,4 +121,5 @@ action,

console.log("waiting for top strong match", target);
const strongMatch = await waitFor(() => {
console.log("waiting for top strong match", target);
const elements = queryActionElements(action);

@@ -88,0 +126,0 @@ return topMatch({

import * as types from "@qawolf/types";
import { getDescriptor } from "./element";
import { findClickableAncestor } from "./find";

@@ -56,9 +57,24 @@ type EventCallback = types.Callback<types.Event>;

private recordEvents() {
this.recordEvent("click", event => ({
isTrusted: event.isTrusted,
name: "click",
target: getDescriptor(event.target as HTMLElement, this._dataAttribute),
time: Date.now()
}));
this.recordEvent("click", event => {
// findClickableAncestor chooses the ancestor if it has a data-attribute
// which is very likely the target we want to click on.
// If there is not a data-attribute on any of the clickable ancestors
// it will take the top most clickable ancestor.
// The ancestor is likely a better target than the descendant.
// Ex. when you click on the i (button > i) or rect (a > svg > rect)
// chances are the ancestor (button, a) is a better target to find.
// XXX if anyone runs into issues with this behavior we can allow disabling it from a flag.
const target = findClickableAncestor(
event.target as HTMLElement,
this._dataAttribute
);
return {
isTrusted: event.isTrusted,
name: "click",
target: getDescriptor(target, this._dataAttribute),
time: Date.now()
};
});
this.recordEvent("input", event => {

@@ -65,0 +81,0 @@ const element = event.target as HTMLInputElement;

@@ -23,3 +23,3 @@ export const sleep = (milliseconds: number): Promise<void> => {

export const waitUntil = async (
booleanFn: () => boolean,
booleanFn: () => boolean | Promise<boolean>,
timeoutMs: number,

@@ -31,3 +31,3 @@ sleepMs: number = 500

while (Date.now() - startTime < timeoutMs) {
const conditionMet = booleanFn();
const conditionMet = await booleanFn();
if (conditionMet) return;

@@ -34,0 +34,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc