donobu
Version:
Create browser automations with an LLM agent and replay them as Playwright scripts.
138 lines • 5.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.InputFakerTool = exports.InputFakerGptSchema = exports.InputFakerNonGptSchema = exports.InputFakerCoreSchema = exports.FAKER_DATA_TYPES = void 0;
const faker_1 = require("@faker-js/faker");
const v4_1 = require("zod/v4");
const MiscUtils_1 = require("../utils/MiscUtils");
const TargetUtils_1 = require("../utils/TargetUtils");
const ReplayableInteraction_1 = require("./ReplayableInteraction");
exports.FAKER_DATA_TYPES = [
// Person
'person.fullName',
'person.firstName',
'person.lastName',
'person.jobTitle',
'person.jobArea',
// Internet
'internet.email',
'internet.username',
'internet.password',
'internet.url',
'internet.domainName',
'internet.ipv4',
// Phone
'phone.number',
// Location
'location.streetAddress',
'location.city',
'location.state',
'location.country',
'location.zipCode',
// Company
'company.name',
'company.catchPhrase',
// Finance
'finance.accountNumber',
'finance.creditCardNumber',
'finance.currencyCode',
// Date
'date.birthdate',
'date.past',
'date.future',
// Lorem
'lorem.word',
'lorem.sentence',
'lorem.paragraph',
// Number / string
'number.int',
'string.uuid',
'string.alphanumeric',
'color.human',
];
exports.InputFakerCoreSchema = v4_1.z.object({
dataType: v4_1.z
.enum(exports.FAKER_DATA_TYPES)
.describe('The type of realistic data to generate and input. Each value maps to a Faker.js data category.'),
append: v4_1.z
.boolean()
.optional()
.describe('If true, append the generated value to the existing contents of the input, rather than clearing it first. Defaults to false.'),
finalizeWithSubmit: v4_1.z
.boolean()
.optional()
.describe("Attempt to submit the data after inputting the generated value (i.e. hitting 'Enter' at the end). " +
"This can be useful if doing something like using a webpage's search box, etc."),
});
exports.InputFakerNonGptSchema = v4_1.z.object({
...ReplayableInteraction_1.SelectorBasedSchema.shape,
...exports.InputFakerCoreSchema.shape,
});
exports.InputFakerGptSchema = v4_1.z.object({
...ReplayableInteraction_1.AnnotationBasedSchema.shape,
...exports.InputFakerCoreSchema.shape,
});
class InputFakerTool extends ReplayableInteraction_1.ReplayableInteraction {
constructor() {
super(InputFakerTool.NAME, "Input a randomly generated, realistic value into a webpage's text input box. " +
'The generated value is drawn from a real-world data category (e.g. a person name, email address, ' +
'street address, company name, etc.) and will look plausible to a human. ' +
'A new value is generated on every invocation.', exports.InputFakerCoreSchema, exports.InputFakerNonGptSchema, exports.InputFakerGptSchema);
}
async invoke(context, parameters, handles) {
const element = handles.target;
const text = InputFakerTool.generate(parameters.dataType);
if (!parameters.append) {
await this.clearField(element);
}
// Focus the element, then type via the page keyboard rather than holding
// a reference to a specific DOM node. This survives mid-sequence DOM
// replacement: if a reactive widget (e.g. Wikipedia's CDX search) swaps
// the <input> on the first keydown, the replacement receives focus and
// subsequent keystrokes are delivered there automatically.
await element.focus();
const page = (0, TargetUtils_1.webPage)(context);
await context.interactionVisualizer.pointAt(page, element);
for (const char of text) {
await page.keyboard.press(char, {
delay: MiscUtils_1.MiscUtils.generateHumanLikeKeyPressDurationInMs(char),
});
}
if (parameters.finalizeWithSubmit) {
const enterKey = 'Enter';
await page.keyboard.press(enterKey, {
delay: MiscUtils_1.MiscUtils.generateHumanLikeKeyPressDurationInMs(enterKey),
});
}
return `Inputted generated value '${text}' into: `;
}
/**
* Generates a value for the given data type using Faker.js.
* Exported as a static method so the Playwright helper and code generator
* can call it directly without instantiating the tool.
*/
static generate(dataType) {
const [module, method] = dataType.split('.');
const value = faker_1.faker[module][method]();
return String(value instanceof Date ? value.toISOString().slice(0, 10) : value);
}
async clearField(element) {
try {
const value = await element.inputValue();
if (value !== '') {
await element.selectText({ timeout: 3000 });
const backspaceKey = 'Backspace';
await element.press(backspaceKey, {
delay: MiscUtils_1.MiscUtils.generateHumanLikeKeyPressDurationInMs(backspaceKey),
timeout: 3000,
});
}
}
catch (_e) {
// This can happen if the element is not a text element, but still accepts text inputs.
// Pass.
}
}
}
exports.InputFakerTool = InputFakerTool;
InputFakerTool.NAME = 'inputFaker';
//# sourceMappingURL=InputFakerTool.js.map