donobu
Version:
Create browser automations with an LLM agent and replay them as Playwright scripts.
169 lines • 7.06 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SmartSelectorImpl = void 0;
const playwright_core_1 = require("playwright-core");
const ChooseSelectOptionTool_1 = require("../../tools/ChooseSelectOptionTool");
const ClickTool_1 = require("../../tools/ClickTool");
const DoubleClickTool_1 = require("../../tools/DoubleClickTool");
const HoverOverElementTool_1 = require("../../tools/HoverOverElementTool");
const InputFakerTool_1 = require("../../tools/InputFakerTool");
const InputRandomizedEmailAddressTool_1 = require("../../tools/InputRandomizedEmailAddressTool");
const InputTextTool_1 = require("../../tools/InputTextTool");
const PressKeyTool_1 = require("../../tools/PressKeyTool");
const ScrollPageTool_1 = require("../../tools/ScrollPageTool");
const PlaywrightUtils_1 = require("../../utils/PlaywrightUtils");
class SmartSelectorImpl {
constructor(page, selector) {
this.page = page;
this.selector = selector;
}
async selectOption(optionValues) {
await this.page.run(ChooseSelectOptionTool_1.ChooseSelectOptionTool.NAME, {
optionValues: optionValues,
selector: this.selector,
});
}
async dblclick() {
await this.page.run(DoubleClickTool_1.DoubleClickTool.NAME, {
selector: this.selector,
});
}
async click(button) {
await this.page.run(ClickTool_1.ClickTool.NAME, {
button: button,
selector: this.selector,
});
}
async hover() {
await this.page.run(HoverOverElementTool_1.HoverOverElementTool.NAME, {
selector: this.selector,
});
}
async inputRandomizedEmailAddress(baseEmail, options) {
const result = await this.page.run(InputRandomizedEmailAddressTool_1.InputRandomizedEmailAddressTool.NAME, {
baseEmail: baseEmail,
finalizeWithSubmit: options?.submit ?? options?.finalizeWithSubmit ?? false,
selector: this.selector,
});
const email = result.forLlm.match(/^Inputted email: "([^"]+)"/)?.[1] ?? result.forLlm;
return email;
}
async inputText(text, options) {
await this.page.run(InputTextTool_1.InputTextTool.NAME, {
text: text,
append: options?.append,
finalizeWithSubmit: options?.submit ?? options?.finalizeWithSubmit ?? false,
selector: this.selector,
});
}
async inputFaker(dataType, options) {
await this.page.run(InputFakerTool_1.InputFakerTool.NAME, {
dataType: dataType,
append: options?.append,
finalizeWithSubmit: options?.submit ?? options?.finalizeWithSubmit ?? false,
selector: this.selector,
});
}
async pressKey(key) {
await this.page.run(PressKeyTool_1.PressKeyTool.NAME, {
key: key,
selector: this.selector,
});
}
async scroll(direction, options) {
await this.page.run(ScrollPageTool_1.ScrollPageTool.NAME, {
direction: direction,
selector: this.selector,
maxScroll: options?.maxScroll,
});
}
async waitFor(options) {
const selectorLocators = await this.getLocatorCandidates();
const attemptedSelectors = selectorLocators.map((candidate) => candidate.selector);
const describeSelectors = (selectors) => {
return selectors.length > 0
? selectors.join(', ')
: this.selector.element.join(', ');
};
let lastTimeoutError = null;
const hasTimeoutBudget = typeof options?.timeout === 'number' && options.timeout >= 0;
const timeoutBudget = hasTimeoutBudget ? options.timeout : undefined;
const startTime = hasTimeoutBudget ? Date.now() : null;
for (const selectorLocator of selectorLocators) {
try {
let waitForOptions = options;
if (hasTimeoutBudget) {
const elapsed = Date.now() - (startTime ?? 0);
const remainingTimeout = timeoutBudget - elapsed;
if (remainingTimeout <= 0) {
throw new playwright_core_1.errors.TimeoutError(`Timed out waiting for selector(s): ${describeSelectors(attemptedSelectors)}`);
}
waitForOptions = {
...options,
timeout: remainingTimeout,
};
}
await selectorLocator.locator.waitFor(waitForOptions);
return selectorLocator.locator;
}
catch (error) {
if (PlaywrightUtils_1.PlaywrightUtils.isPageClosedError(error)) {
throw error;
}
if (isTimeoutLikeError(error)) {
lastTimeoutError =
error instanceof Error
? error
: new playwright_core_1.errors.TimeoutError(String(error));
continue;
}
throw error;
}
}
if (lastTimeoutError) {
throw new playwright_core_1.errors.TimeoutError(`Timed out waiting for selector(s): ${describeSelectors(attemptedSelectors)}. Last error: ${lastTimeoutError instanceof Error ? lastTimeoutError.message : String(lastTimeoutError)}`);
}
throw new playwright_core_1.errors.TimeoutError(`Timed out waiting for selector(s): ${describeSelectors(attemptedSelectors)}`);
}
async getLocatorCandidates() {
const selectorLocators = [];
const seenSelectors = new Set();
for (const selectorCandidate of this.selector.element) {
const normalized = PlaywrightUtils_1.PlaywrightUtils.normalizeSelector(selectorCandidate);
if (seenSelectors.has(normalized)) {
continue;
}
const locator = this.selector.frame
? this.page.frameLocator(this.selector.frame).locator(normalized)
: this.page.locator(normalized);
selectorLocators.push({
selector: normalized,
locator: locator,
});
seenSelectors.add(normalized);
}
return selectorLocators;
}
}
exports.SmartSelectorImpl = SmartSelectorImpl;
function isTimeoutLikeError(error) {
if (error instanceof playwright_core_1.errors.TimeoutError) {
return true;
}
if (typeof error === 'string') {
return error.toLowerCase().includes('timeout');
}
if (error && typeof error === 'object') {
const timeoutName = error.name;
if (timeoutName === 'TimeoutError') {
return true;
}
const message = error.message;
if (typeof message === 'string' &&
message.toLowerCase().includes('timeout')) {
return true;
}
}
return false;
}
//# sourceMappingURL=SmartSelector.js.map