brave-real-browser-mcp-server 2.4.2 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -3,6 +3,7 @@ import { withErrorHandling } from '../system-utils.js';
|
|
|
3
3
|
import { validateWorkflow, recordExecution, workflowValidator } from '../workflow-validation.js';
|
|
4
4
|
import { selfHealingLocators } from '../self-healing-locators.js';
|
|
5
5
|
import { randomScroll } from '../stealth-actions.js';
|
|
6
|
+
import { setTimeout as sleep } from 'node:timers/promises';
|
|
6
7
|
// Click handler
|
|
7
8
|
export async function handleClick(args) {
|
|
8
9
|
return await withWorkflowValidation('click', args, async () => {
|
|
@@ -117,18 +118,62 @@ export async function handleType(args) {
|
|
|
117
118
|
try {
|
|
118
119
|
// Wait for element to be ready and interactable
|
|
119
120
|
await pageInstance.waitForSelector(usedSelector, { timeout: 5000 });
|
|
120
|
-
//
|
|
121
|
-
await
|
|
122
|
-
// Clear existing content
|
|
123
|
-
await pageInstance.evaluate((sel) => {
|
|
121
|
+
// Check if element is a dropdown/select
|
|
122
|
+
const isDropdown = await pageInstance.evaluate((sel) => {
|
|
124
123
|
const el = document.querySelector(sel);
|
|
125
|
-
|
|
126
|
-
el.select();
|
|
127
|
-
el.value = '';
|
|
128
|
-
}
|
|
124
|
+
return el?.tagName.toLowerCase() === 'select';
|
|
129
125
|
}, usedSelector);
|
|
130
|
-
|
|
131
|
-
|
|
126
|
+
if (isDropdown) {
|
|
127
|
+
// Handle dropdown selection with proper event triggering
|
|
128
|
+
await pageInstance.evaluate((sel, value) => {
|
|
129
|
+
const selectEl = document.querySelector(sel);
|
|
130
|
+
if (!selectEl)
|
|
131
|
+
return;
|
|
132
|
+
// Human-like behavior: Focus first
|
|
133
|
+
selectEl.focus();
|
|
134
|
+
// Find option by text or value
|
|
135
|
+
const options = Array.from(selectEl.options);
|
|
136
|
+
const matchedOption = options.find(opt => opt.text.toLowerCase().includes(value.toLowerCase()) ||
|
|
137
|
+
opt.value.toLowerCase().includes(value.toLowerCase()));
|
|
138
|
+
if (matchedOption) {
|
|
139
|
+
// Set the value
|
|
140
|
+
selectEl.value = matchedOption.value;
|
|
141
|
+
// Fire all relevant events for dynamic dropdowns
|
|
142
|
+
selectEl.dispatchEvent(new Event('input', { bubbles: true }));
|
|
143
|
+
selectEl.dispatchEvent(new Event('change', { bubbles: true }));
|
|
144
|
+
selectEl.dispatchEvent(new Event('blur', { bubbles: true }));
|
|
145
|
+
// Trigger jQuery change event if jQuery exists
|
|
146
|
+
if (typeof window.jQuery !== 'undefined') {
|
|
147
|
+
window.jQuery(selectEl).trigger('change');
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}, usedSelector, text);
|
|
151
|
+
// Wait a bit for dependent dropdowns to load
|
|
152
|
+
await sleep(1500);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
// Regular input field
|
|
156
|
+
// Focus on the element first
|
|
157
|
+
await element.focus();
|
|
158
|
+
// Clear existing content
|
|
159
|
+
await pageInstance.evaluate((sel) => {
|
|
160
|
+
const el = document.querySelector(sel);
|
|
161
|
+
if (el) {
|
|
162
|
+
el.select();
|
|
163
|
+
el.value = '';
|
|
164
|
+
}
|
|
165
|
+
}, usedSelector);
|
|
166
|
+
// Type the new text with human-like delay
|
|
167
|
+
await pageInstance.type(usedSelector, text, { delay });
|
|
168
|
+
// Fire events for dynamic forms
|
|
169
|
+
await pageInstance.evaluate((sel) => {
|
|
170
|
+
const el = document.querySelector(sel);
|
|
171
|
+
if (el) {
|
|
172
|
+
el.dispatchEvent(new Event('input', { bubbles: true }));
|
|
173
|
+
el.dispatchEvent(new Event('change', { bubbles: true }));
|
|
174
|
+
}
|
|
175
|
+
}, usedSelector);
|
|
176
|
+
}
|
|
132
177
|
return {
|
|
133
178
|
content: [
|
|
134
179
|
{
|