UNPKG

donobu

Version:

Create browser automations with an LLM agent and replay them as Playwright scripts.

169 lines 7.06 kB
"use strict"; 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