real-browser-mcp-server 1.0.10 → 1.1.2

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.
package/README.md CHANGED
@@ -35,7 +35,7 @@ npx patchright install chromium
35
35
 
36
36
  * **Undetected Browser Engine**: Powered by **Patchright Chromium**, bypassing modern fingerprinting checks (does not expose automation indicators or Webdriver/BiDi flags).
37
37
  * **Integrated Ad & Tracker Blocker**: Utilizes `@ghostery/adblocker-playwright` with asynchronous pre-compiled filter caching to `adblocker.bin`, blocking ads and speed-bumps completely offline.
38
- * **Human-like Interactions**: Integrates **ghost-cursor-patchright** (Bézier curves) to transparently simulate human mouse movements, velocity, and natural hover-before-click behaviors.
38
+ * **Human-like Interactions**: Integrates **ghost-cursor-patchright** (Bézier curves) to transparently simulate human mouse movements, velocity, and natural hover-before-click behaviors. Features **Physics-based Smooth Scrolling** (`page.realScroll`) utilizing real mouse-wheel events and Cubic Ease-Out deceleration to perfectly mimic manual trackpad/mouse flicks, bypassing advanced behavioral detectors.
39
39
  * **Turnstile Auto-Solver**: Seamlessly detects and bypasses Cloudflare Turnstile widgets.
40
40
  * **Anti-Race Condition Guards**: Robust state-guards ensure popup blockers, shims, and adblockers attach exactly once per page, preventing context destruction.
41
41
 
@@ -158,7 +158,7 @@ The server exposes 22 highly optimized tools categorized into functional units:
158
158
  | `click` | Human-like click using AI healing, ghost cursor, and iframe support. | `selector` (string), `hoverFirst` (boolean) |
159
159
  | `type` | Type text with human speed variation, smart clearing, and iframe support. | `selector` (string), `text` (string) |
160
160
  | `solve_captcha` | Auto-solve CAPTCHAs (Turnstile, reCAPTCHA, hCaptcha, OCR). | `selector` (string) |
161
- | `random_scroll` | Simulated human scrolling with natural patterns and lazy-load triggers. | `direction` (string), `amount` (number) |
161
+ | `random_scroll` | Simulated human scrolling with natural patterns and lazy-load triggers. | `direction` (string), `amount` (number), `smooth` (boolean) |
162
162
  | `press_key` | Press keyboard keys with modifier key support (Ctrl/Shift/Alt). | `key` (string), `modifiers` (array) |
163
163
  | `execute_js` | Run custom asynchronous/synchronous JavaScript inside a page or iframe. | `code` (string), `iframeIndex` (number) |
164
164
 
@@ -213,6 +213,11 @@ Both the CommonJS and ES Module test suites execute and pass successfully under
213
213
  | **CommonJS (`cjs_test`)** | Fingerprint JS Bot Detector | ✅ Passed |
214
214
  | **CommonJS (`cjs_test`)** | Recaptcha V3 Score | ✅ Passed |
215
215
  | **CommonJS (`cjs_test`)** | Pixelscan Fingerprint Check | ✅ Passed |
216
+ | **CommonJS (`cjs_test`)** | Human-like Move & Click | ✅ Passed |
217
+ | **CommonJS (`cjs_test`)** | Human-like Typing | ✅ Passed |
218
+ | **CommonJS (`cjs_test`)** | Human-like Scrolling | ✅ Passed |
219
+ | **CommonJS (`cjs_test`)** | Form Automation Demonstration | ✅ Passed |
220
+ | **CommonJS (`cjs_test`)** | Content Strategy Demonstration | ✅ Passed |
216
221
  | **ES Module (`esm_test`)** | DrissionPage Detector | ✅ Passed |
217
222
  | **ES Module (`esm_test`)** | Sannysoft WebDriver Detector | ✅ Passed |
218
223
  | **ES Module (`esm_test`)** | Cloudflare WAF | ✅ Passed |
@@ -220,6 +225,11 @@ Both the CommonJS and ES Module test suites execute and pass successfully under
220
225
  | **ES Module (`esm_test`)** | Fingerprint JS Bot Detector | ✅ Passed |
221
226
  | **ES Module (`esm_test`)** | Recaptcha V3 Score | ✅ Passed |
222
227
  | **ES Module (`esm_test`)** | Pixelscan Fingerprint Check | ✅ Passed |
228
+ | **ES Module (`esm_test`)** | Human-like Move & Click | ✅ Passed |
229
+ | **ES Module (`esm_test`)** | Human-like Typing | ✅ Passed |
230
+ | **ES Module (`esm_test`)** | Human-like Scrolling | ✅ Passed |
231
+ | **ES Module (`esm_test`)** | Form Automation Demonstration | ✅ Passed |
232
+ | **ES Module (`esm_test`)** | Content Strategy Demonstration | ✅ Passed |
223
233
 
224
234
  ---
225
235
 
@@ -244,6 +254,9 @@ const { connect } = require('real-browser-mcp-server');
244
254
  // Real mouse movement and click
245
255
  await page.realClick('#my-button');
246
256
 
257
+ // Real human-like smooth scrolling (60FPS Cubic Ease-Out physics)
258
+ await page.realScroll(400); // scrolls down 400px smoothly
259
+
247
260
  await browser.close();
248
261
  })();
249
262
  ```
@@ -259,6 +272,10 @@ const { browser, page } = await connect({
259
272
 
260
273
  await page.goto('https://example.com');
261
274
  await page.realClick('#my-button');
275
+
276
+ // Real human-like smooth scrolling (60FPS Cubic Ease-Out physics)
277
+ await page.realScroll(400); // scrolls down 400px smoothly
278
+
262
279
  await browser.close();
263
280
  ```
264
281
 
package/lib/cjs/index.js CHANGED
@@ -66,8 +66,23 @@ function loadEnvFile() {
66
66
  loadEnvFile();
67
67
 
68
68
  function getDefaultHeadless() {
69
- const envHeadless = (process.env.HEADLESS || '').toLowerCase();
70
- return envHeadless === 'true';
69
+ const envHeadless = process.env.HEADLESS;
70
+ if (envHeadless !== undefined && envHeadless !== null && envHeadless !== '') {
71
+ const value = envHeadless.toLowerCase().trim();
72
+ return value === 'true' || value === '1' || value === 'yes';
73
+ }
74
+ // Auto-detect CI environments
75
+ if (process.env.CI || process.env.GITHUB_ACTIONS || process.env.TRAVIS || process.env.CIRCLECI) {
76
+ return true;
77
+ }
78
+ // Auto-detect headless Linux environments without X11 or Wayland
79
+ if (process.platform === 'linux') {
80
+ const hasDisplay = process.env.DISPLAY || process.env.WAYLAND_DISPLAY;
81
+ if (!hasDisplay) {
82
+ return true;
83
+ }
84
+ }
85
+ return false;
71
86
  }
72
87
 
73
88
  function setupRealPage(browser, page) {
@@ -85,6 +100,29 @@ function setupRealPage(browser, page) {
85
100
  });
86
101
  }
87
102
 
103
+ // Human-like smooth scrolling with 60FPS Cubic Ease-Out physics
104
+ page.realScroll = async (deltaY, duration = 600) => {
105
+ try {
106
+ const stepDelay = 15; // ~60 FPS
107
+ const steps = Math.max(10, Math.floor(duration / stepDelay));
108
+ const easeOutCubic = (t) => 1 - Math.pow(1 - t, 3);
109
+ let currentScroll = 0;
110
+ for (let i = 1; i <= steps; i++) {
111
+ const t = i / steps;
112
+ const targetScroll = deltaY * easeOutCubic(t);
113
+ const diff = targetScroll - currentScroll;
114
+ await page.mouse.wheel(0, diff);
115
+ currentScroll = targetScroll;
116
+ await new Promise(r => setTimeout(r, stepDelay));
117
+ }
118
+ } catch (e) {
119
+ // Fallback to native window scroll in case of wheel errors
120
+ try {
121
+ await page.evaluate((y) => window.scrollBy({ top: y, behavior: 'smooth' }), deltaY);
122
+ } catch (_) {}
123
+ }
124
+ };
125
+
88
126
  // Ghost Cursor integration - Bézier curve human-like mouse movement
89
127
  try {
90
128
  const cursor = createCursor(page);
@@ -123,6 +161,7 @@ function setupRealPage(browser, page) {
123
161
  }
124
162
 
125
163
  return page;
164
+
126
165
  }
127
166
 
128
167
  function getBraveExecutablePath() {
package/lib/esm/index.mjs CHANGED
@@ -71,8 +71,23 @@ function loadEnvFile() {
71
71
  loadEnvFile();
72
72
 
73
73
  function getDefaultHeadless() {
74
- const envHeadless = (process.env.HEADLESS || '').toLowerCase();
75
- return envHeadless === 'true';
74
+ const envHeadless = process.env.HEADLESS;
75
+ if (envHeadless !== undefined && envHeadless !== null && envHeadless !== '') {
76
+ const value = envHeadless.toLowerCase().trim();
77
+ return value === 'true' || value === '1' || value === 'yes';
78
+ }
79
+ // Auto-detect CI environments
80
+ if (process.env.CI || process.env.GITHUB_ACTIONS || process.env.TRAVIS || process.env.CIRCLECI) {
81
+ return true;
82
+ }
83
+ // Auto-detect headless Linux environments without X11 or Wayland
84
+ if (process.platform === 'linux') {
85
+ const hasDisplay = process.env.DISPLAY || process.env.WAYLAND_DISPLAY;
86
+ if (!hasDisplay) {
87
+ return true;
88
+ }
89
+ }
90
+ return false;
76
91
  }
77
92
 
78
93
  function setupRealPage(browser, page) {
@@ -90,6 +105,29 @@ function setupRealPage(browser, page) {
90
105
  });
91
106
  }
92
107
 
108
+ // Human-like smooth scrolling with 60FPS Cubic Ease-Out physics
109
+ page.realScroll = async (deltaY, duration = 600) => {
110
+ try {
111
+ const stepDelay = 15; // ~60 FPS
112
+ const steps = Math.max(10, Math.floor(duration / stepDelay));
113
+ const easeOutCubic = (t) => 1 - Math.pow(1 - t, 3);
114
+ let currentScroll = 0;
115
+ for (let i = 1; i <= steps; i++) {
116
+ const t = i / steps;
117
+ const targetScroll = deltaY * easeOutCubic(t);
118
+ const diff = targetScroll - currentScroll;
119
+ await page.mouse.wheel(0, diff);
120
+ currentScroll = targetScroll;
121
+ await new Promise(r => setTimeout(r, stepDelay));
122
+ }
123
+ } catch (e) {
124
+ // Fallback to native window scroll in case of wheel errors
125
+ try {
126
+ await page.evaluate((y) => window.scrollBy({ top: y, behavior: 'smooth' }), deltaY);
127
+ } catch (_) {}
128
+ }
129
+ };
130
+
93
131
  // Ghost Cursor integration - Bézier curve human-like mouse movement
94
132
  try {
95
133
  const cursor = createCursor(page);
@@ -128,6 +166,7 @@ function setupRealPage(browser, page) {
128
166
  }
129
167
 
130
168
  return page;
169
+
131
170
  }
132
171
 
133
172
  function getBraveExecutablePath() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "real-browser-mcp-server",
3
- "version": "1.0.10",
3
+ "version": "1.1.2",
4
4
  "description": "MCP Server for Real Browser - Patchright (undetected Playwright fork) with Stealth Mode, Ad Blocker, and Turnstile Auto-Solver for undetectable web automation.",
5
5
  "main": "lib/cjs/index.js",
6
6
  "module": "lib/esm/index.mjs",
@@ -68,13 +68,25 @@ function notifyProgress(toolName, status, message, data = {}) {
68
68
  function getHeadlessFromEnv() {
69
69
  const envHeadless = process.env.HEADLESS;
70
70
 
71
- if (envHeadless === undefined || envHeadless === null || envHeadless === '') {
72
- return false; // Default: GUI mode
71
+ if (envHeadless !== undefined && envHeadless !== null && envHeadless !== '') {
72
+ const value = envHeadless.toLowerCase().trim();
73
+ return value === 'true' || value === '1' || value === 'yes';
73
74
  }
74
75
 
75
- // Parse string to boolean
76
- const value = envHeadless.toLowerCase().trim();
77
- return value === 'true' || value === '1' || value === 'yes';
76
+ // Auto-detect CI environments
77
+ if (process.env.CI || process.env.GITHUB_ACTIONS || process.env.TRAVIS || process.env.CIRCLECI) {
78
+ return true;
79
+ }
80
+
81
+ // Auto-detect headless Linux environments without X11 or Wayland
82
+ if (process.platform === 'linux') {
83
+ const hasDisplay = process.env.DISPLAY || process.env.WAYLAND_DISPLAY;
84
+ if (!hasDisplay) {
85
+ return true;
86
+ }
87
+ }
88
+
89
+ return false;
78
90
  }
79
91
 
80
92
  /**
@@ -2049,10 +2061,14 @@ const handlers = {
2049
2061
 
2050
2062
  notifyProgress('random_scroll', 'started', `Scrolling ${scrollDirection} ${scrollAmount}px`);
2051
2063
 
2052
- await page.evaluate(({ scrollAmount, scrollDirection, smooth }) => {
2053
- const y = scrollDirection === 'down' ? scrollAmount : -scrollAmount;
2054
- window.scrollBy({ top: y, behavior: smooth ? 'smooth' : 'auto' });
2055
- }, { scrollAmount, scrollDirection, smooth });
2064
+ const y = scrollDirection === 'down' ? scrollAmount : -scrollAmount;
2065
+ if (smooth && page.realScroll) {
2066
+ await page.realScroll(y, 600);
2067
+ } else {
2068
+ await page.evaluate(({ y, smooth }) => {
2069
+ window.scrollBy({ top: y, behavior: smooth ? 'smooth' : 'auto' });
2070
+ }, { y, smooth });
2071
+ }
2056
2072
 
2057
2073
  notifyProgress('random_scroll', 'completed', `Scrolled ${scrollDirection} ${scrollAmount}px`, { direction: scrollDirection, amount: scrollAmount });
2058
2074
 
package/test/cjs/test.js CHANGED
@@ -4,7 +4,7 @@ const { connect } = require('../../lib/cjs/index.js');
4
4
 
5
5
  const realBrowserOption = {
6
6
  turnstile: true,
7
- headless: true,
7
+ headless: false,
8
8
  customConfig: {}
9
9
  }
10
10
 
@@ -30,6 +30,126 @@ test.after(async () => {
30
30
  }
31
31
  });
32
32
 
33
+ test('Human-like Move & Click', async () => {
34
+ await page.goto("https://www.google.com", { timeout: 40000 });
35
+ const selector = 'textarea[name="q"], input[name="q"]';
36
+ await page.realCursor.move(selector);
37
+ await page.realClick(selector);
38
+ assert.ok(true);
39
+ })
40
+
41
+ test('Human-like Typing', async () => {
42
+ await page.goto("https://www.google.com", { timeout: 40000 });
43
+ const selector = 'textarea[name="q"], input[name="q"]';
44
+ await page.realCursor.move(selector);
45
+ await page.realClick(selector);
46
+ await page.type(selector, 'Real Browser MCP Server', { delay: 150 });
47
+ const val = await page.inputValue(selector);
48
+ assert.strictEqual(val, 'Real Browser MCP Server');
49
+ })
50
+
51
+ test('Human-like Scrolling', async () => {
52
+ await page.goto("https://www.google.com/search?q=Real+Browser+MCP+Server", { timeout: 40000, waitUntil: 'domcontentloaded' });
53
+ await new Promise(r => setTimeout(r, 2000));
54
+
55
+ console.log('📜 Scrolling down smoothly and fast (400px)...');
56
+ await page.realScroll(400, 500);
57
+ await new Promise(r => setTimeout(r, 600));
58
+
59
+ console.log('📜 Scrolling down smoothly and fast (300px)...');
60
+ await page.realScroll(300, 400);
61
+ await new Promise(r => setTimeout(r, 600));
62
+
63
+ console.log('📜 Scrolling up smoothly and fast (-500px)...');
64
+ await page.realScroll(-500, 600);
65
+ await new Promise(r => setTimeout(r, 1000));
66
+
67
+ assert.ok(true);
68
+ })
69
+
70
+ test('Form Automation Demonstration', async () => {
71
+ console.log('\n🎬 DEMO: Form Automation');
72
+ try {
73
+ await page.goto('https://httpbin.org/forms/post', { timeout: 30000 });
74
+ console.log('\n4️⃣ Filling out form...');
75
+
76
+ // 1. Customer Name
77
+ await page.type('input[name="custname"]', 'John Doe', { delay: 100 });
78
+ console.log('✅ Customer Name filled');
79
+
80
+ // 2. Telephone
81
+ await page.type('input[name="custtel"]', '+1-555-0199', { delay: 100 });
82
+ console.log('✅ Telephone filled');
83
+
84
+ // 3. Email address
85
+ await page.type('input[name="custemail"]', 'john.doe@example.com', { delay: 100 });
86
+ console.log('✅ Email field filled');
87
+
88
+ // 4. Pizza Size (Radio Button)
89
+ await page.realClick('input[value="medium"]');
90
+ console.log('✅ Pizza Size selected (Medium)');
91
+
92
+ // 5. Pizza Toppings (Checkboxes)
93
+ await page.realClick('input[value="bacon"]');
94
+ await page.realClick('input[value="onion"]');
95
+ console.log('✅ Toppings selected (Bacon, Onion)');
96
+
97
+ // 6. Preferred Delivery Time
98
+ await page.type('input[name="delivery"]', '13:00', { delay: 100 });
99
+ console.log('✅ Delivery time filled');
100
+
101
+ // 7. Delivery Instructions (Comments)
102
+ await page.type('textarea[name="comments"]', 'Leave at the front door, please.', { delay: 100 });
103
+ console.log('✅ Delivery instructions filled');
104
+
105
+ // Wait 2 seconds for visual demonstration
106
+ await new Promise(resolve => setTimeout(resolve, 2000));
107
+
108
+ // 8. Submit Order
109
+ await page.realClick('form button');
110
+ console.log('✅ Form submitted successfully');
111
+
112
+ await new Promise(resolve => setTimeout(resolve, 2000));
113
+ console.log('\n🎉 FORM AUTOMATION COMPLETE!');
114
+ } catch (error) {
115
+ console.error('❌ Form automation test failed:', error);
116
+ throw error;
117
+ }
118
+ })
119
+
120
+ test('Content Strategy Demonstration', async () => {
121
+ console.log('\n🎬 DEMO: Content Analysis & Token Management');
122
+ console.log('👀 Watch browser analyze content from different websites');
123
+ try {
124
+ const testSites = [
125
+ { url: 'https://httpbin.org/html', description: 'Simple HTML page' },
126
+ { url: 'https://example.com', description: 'Minimal content page' }
127
+ ];
128
+
129
+ for (const [index, site] of testSites.entries()) {
130
+ console.log(`\n${index + 2}️⃣ Testing ${site.description}: ${site.url}`);
131
+ await page.goto(site.url, { waitUntil: 'domcontentloaded', timeout: 30000 });
132
+ await new Promise(resolve => setTimeout(resolve, 2000));
133
+
134
+ console.log(` 📄 Getting HTML content...`);
135
+ const htmlContent = await page.content();
136
+ console.log(` ✅ HTML analyzed: ${htmlContent.length} characters`);
137
+
138
+ console.log(` 📝 Getting text content...`);
139
+ const textContent = await page.evaluate(() => document.body.innerText);
140
+ console.log(` ✅ Text analyzed: ${textContent.length} characters`);
141
+
142
+ assert.ok(htmlContent.length > 0);
143
+ assert.ok(textContent.length > 0);
144
+ await new Promise(resolve => setTimeout(resolve, 1500));
145
+ }
146
+ console.log('\n🎉 CONTENT ANALYSIS COMPLETE!');
147
+ } catch (error) {
148
+ console.error('❌ Content strategy test failed:', error);
149
+ throw error;
150
+ }
151
+ })
152
+
33
153
  test('DrissionPage Detector', async () => {
34
154
  await page.goto("https://web.archive.org/web/20240913054632/https://drissionpage.pages.dev/", { timeout: 60000 });
35
155
  await page.realClick("#detector")
@@ -210,3 +330,7 @@ test('Pixelscan Fingerprint Check', async () => {
210
330
  assert.strictEqual(result, true, "Pixelscan Fingerprint Check failed! Browser fingerprint is inconsistent or masking was detected.");
211
331
  })
212
332
 
333
+
334
+
335
+
336
+
package/test/esm/test.mjs CHANGED
@@ -4,7 +4,7 @@ import { connect } from '../../lib/esm/index.mjs';
4
4
 
5
5
  const realBrowserOption = {
6
6
  turnstile: true,
7
- headless: true,
7
+ headless: false,
8
8
  customConfig: {}
9
9
  }
10
10
 
@@ -30,6 +30,126 @@ test.after(async () => {
30
30
  }
31
31
  });
32
32
 
33
+ test('Human-like Move & Click', async () => {
34
+ await page.goto("https://www.google.com", { timeout: 40000 });
35
+ const selector = 'textarea[name="q"], input[name="q"]';
36
+ await page.realCursor.move(selector);
37
+ await page.realClick(selector);
38
+ assert.ok(true);
39
+ })
40
+
41
+ test('Human-like Typing', async () => {
42
+ await page.goto("https://www.google.com", { timeout: 40000 });
43
+ const selector = 'textarea[name="q"], input[name="q"]';
44
+ await page.realCursor.move(selector);
45
+ await page.realClick(selector);
46
+ await page.type(selector, 'Real Browser MCP Server', { delay: 150 });
47
+ const val = await page.inputValue(selector);
48
+ assert.strictEqual(val, 'Real Browser MCP Server');
49
+ })
50
+
51
+ test('Human-like Scrolling', async () => {
52
+ await page.goto("https://www.google.com/search?q=Real+Browser+MCP+Server", { timeout: 40000, waitUntil: 'domcontentloaded' });
53
+ await new Promise(r => setTimeout(r, 2000));
54
+
55
+ console.log('📜 Scrolling down smoothly and fast (400px)...');
56
+ await page.realScroll(400, 500);
57
+ await new Promise(r => setTimeout(r, 600));
58
+
59
+ console.log('📜 Scrolling down smoothly and fast (300px)...');
60
+ await page.realScroll(300, 400);
61
+ await new Promise(r => setTimeout(r, 600));
62
+
63
+ console.log('📜 Scrolling up smoothly and fast (-500px)...');
64
+ await page.realScroll(-500, 600);
65
+ await new Promise(r => setTimeout(r, 1000));
66
+
67
+ assert.ok(true);
68
+ })
69
+
70
+ test('Form Automation Demonstration', async () => {
71
+ console.log('\n🎬 DEMO: Form Automation');
72
+ try {
73
+ await page.goto('https://httpbin.org/forms/post', { timeout: 30000 });
74
+ console.log('\n4️⃣ Filling out form...');
75
+
76
+ // 1. Customer Name
77
+ await page.type('input[name="custname"]', 'John Doe', { delay: 100 });
78
+ console.log('✅ Customer Name filled');
79
+
80
+ // 2. Telephone
81
+ await page.type('input[name="custtel"]', '+1-555-0199', { delay: 100 });
82
+ console.log('✅ Telephone filled');
83
+
84
+ // 3. Email address
85
+ await page.type('input[name="custemail"]', 'john.doe@example.com', { delay: 100 });
86
+ console.log('✅ Email field filled');
87
+
88
+ // 4. Pizza Size (Radio Button)
89
+ await page.realClick('input[value="medium"]');
90
+ console.log('✅ Pizza Size selected (Medium)');
91
+
92
+ // 5. Pizza Toppings (Checkboxes)
93
+ await page.realClick('input[value="bacon"]');
94
+ await page.realClick('input[value="onion"]');
95
+ console.log('✅ Toppings selected (Bacon, Onion)');
96
+
97
+ // 6. Preferred Delivery Time
98
+ await page.type('input[name="delivery"]', '13:00', { delay: 100 });
99
+ console.log('✅ Delivery time filled');
100
+
101
+ // 7. Delivery Instructions (Comments)
102
+ await page.type('textarea[name="comments"]', 'Leave at the front door, please.', { delay: 100 });
103
+ console.log('✅ Delivery instructions filled');
104
+
105
+ // Wait 2 seconds for visual demonstration
106
+ await new Promise(resolve => setTimeout(resolve, 2000));
107
+
108
+ // 8. Submit Order
109
+ await page.realClick('form button');
110
+ console.log('✅ Form submitted successfully');
111
+
112
+ await new Promise(resolve => setTimeout(resolve, 2000));
113
+ console.log('\n🎉 FORM AUTOMATION COMPLETE!');
114
+ } catch (error) {
115
+ console.error('❌ Form automation test failed:', error);
116
+ throw error;
117
+ }
118
+ })
119
+
120
+ test('Content Strategy Demonstration', async () => {
121
+ console.log('\n🎬 DEMO: Content Analysis & Token Management');
122
+ console.log('👀 Watch browser analyze content from different websites');
123
+ try {
124
+ const testSites = [
125
+ { url: 'https://httpbin.org/html', description: 'Simple HTML page' },
126
+ { url: 'https://example.com', description: 'Minimal content page' }
127
+ ];
128
+
129
+ for (const [index, site] of testSites.entries()) {
130
+ console.log(`\n${index + 2}️⃣ Testing ${site.description}: ${site.url}`);
131
+ await page.goto(site.url, { waitUntil: 'domcontentloaded', timeout: 30000 });
132
+ await new Promise(resolve => setTimeout(resolve, 2000));
133
+
134
+ console.log(` 📄 Getting HTML content...`);
135
+ const htmlContent = await page.content();
136
+ console.log(` ✅ HTML analyzed: ${htmlContent.length} characters`);
137
+
138
+ console.log(` 📝 Getting text content...`);
139
+ const textContent = await page.evaluate(() => document.body.innerText);
140
+ console.log(` ✅ Text analyzed: ${textContent.length} characters`);
141
+
142
+ assert.ok(htmlContent.length > 0);
143
+ assert.ok(textContent.length > 0);
144
+ await new Promise(resolve => setTimeout(resolve, 1500));
145
+ }
146
+ console.log('\n🎉 CONTENT ANALYSIS COMPLETE!');
147
+ } catch (error) {
148
+ console.error('❌ Content strategy test failed:', error);
149
+ throw error;
150
+ }
151
+ })
152
+
33
153
  test('DrissionPage Detector', async () => {
34
154
  await page.goto("https://web.archive.org/web/20240913054632/https://drissionpage.pages.dev/", { timeout: 70000 });
35
155
  await page.realClick("#detector")
@@ -173,3 +293,7 @@ test('Pixelscan Fingerprint Check', async () => {
173
293
 
174
294
  assert.strictEqual(result, true, "Pixelscan Fingerprint Check failed! Browser fingerprint is inconsistent or masking was detected.");
175
295
  })
296
+
297
+
298
+
299
+