/** * Example tests demonstrating Playwright with human-like behavior * Run with: npx playwright test tests/human-behavior.test.js --headed */ import { test, expect } from '@playwright/test'; import { randomDelay, humanMouseMove, randomMouseMovements, humanScroll, humanClick, humanType, simulateReading, getHumanizedContext } from '../scripts/human-behavior.js'; test.describe('Human-like behavior tests', () => { test('should navigate and search Google with human behavior', async ({ browser }) => { const context = await getHumanizedContext(browser); const page = await context.newPage(); try { // Navigate to Google await page.goto('https://www.google.com'); await randomDelay(1000, 2000); // Random mouse movements await randomMouseMovements(page, 2); // Find search box const searchBox = 'textarea[name="q"], input[name="q"]'; await page.waitForSelector(searchBox); // Click and type with human behavior await humanClick(page, searchBox); await humanType(page, searchBox, 'playwright testing', { minDelay: 80, maxDelay: 200, mistakes: 0.05 }); // Submit search await randomDelay(500, 1000); await page.keyboard.press('Enter'); // Wait for results await page.waitForLoadState('networkidle'); await randomDelay(1500, 2500); // Scroll through results await humanScroll(page, { scrollCount: 3, minScroll: 150, maxScroll: 400, randomDirection: true }); // Simulate reading await simulateReading(page, 3000); // Verify we have results const results = await page.locator('div.g').count(); expect(results).toBeGreaterThan(0); } finally { await page.close(); await context.close(); } }); test('should scroll with natural human patterns', async ({ browser }) => { const context = await getHumanizedContext(browser); const page = await context.newPage(); try { // Navigate to a long page await page.goto('https://en.wikipedia.org/wiki/Web_scraping'); await randomDelay(1000, 2000); // Get initial scroll position const initialScroll = await page.evaluate(() => window.scrollY); // Perform human-like scrolling await humanScroll(page, { scrollCount: 5, minScroll: 100, maxScroll: 300, minDelay: 800, maxDelay: 2000, randomDirection: true }); // Verify page scrolled const finalScroll = await page.evaluate(() => window.scrollY); expect(finalScroll).not.toBe(initialScroll); // Add some random mouse movements await randomMouseMovements(page, 3); } finally { await page.close(); await context.close(); } }); test('should click elements with overshooting', async ({ browser }) => { const context = await getHumanizedContext(browser); const page = await context.newPage(); try { await page.goto('https://www.example.com'); await randomDelay(1000, 1500); // Move mouse around naturally await randomMouseMovements(page, 2); // Click with human behavior (with possible overshoot) const linkSelector = 'a'; await humanClick(page, linkSelector, { overshootChance: 0.3, // 30% chance to overshoot overshootDistance: 25 }); // Wait for navigation await page.waitForLoadState('networkidle'); // Verify navigation occurred const url = page.url(); expect(url).toContain('iana.org'); } finally { await page.close(); await context.close(); } }); test('should simulate realistic reading behavior', async ({ browser }) => { const context = await getHumanizedContext(browser); const page = await context.newPage(); try { await page.goto('https://news.ycombinator.com'); await randomDelay(1000, 2000); const startTime = Date.now(); // Simulate reading for 5 seconds await simulateReading(page, 5000); const elapsed = Date.now() - startTime; // Should have taken at least 5 seconds expect(elapsed).toBeGreaterThanOrEqual(5000); } finally { await page.close(); await context.close(); } }); test('should use randomized browser fingerprints', async ({ browser }) => { // Create multiple contexts and verify they have different fingerprints const contexts = []; try { for (let i = 0; i < 3; i++) { const context = await getHumanizedContext(browser); contexts.push(context); } // Each context should have different settings expect(contexts.length).toBe(3); // Verify different user agents (likely, due to randomization) const page1 = await contexts[0].newPage(); const page2 = await contexts[1].newPage(); const ua1 = await page1.evaluate(() => navigator.userAgent); const ua2 = await page2.evaluate(() => navigator.userAgent); // Both should be valid user agents expect(ua1).toBeTruthy(); expect(ua2).toBeTruthy(); await page1.close(); await page2.close(); } finally { for (const context of contexts) { await context.close(); } } }); test('should type with realistic mistakes and corrections', async ({ browser }) => { const context = await getHumanizedContext(browser); const page = await context.newPage(); try { await page.goto('https://www.google.com'); await randomDelay(1000, 1500); const searchBox = 'textarea[name="q"], input[name="q"]'; await page.waitForSelector(searchBox); // Type with high mistake chance for testing await humanClick(page, searchBox); await humanType(page, searchBox, 'testing human behavior', { minDelay: 50, maxDelay: 120, mistakes: 0.1 // 10% mistake rate for testing }); // Get the input value const value = await page.inputValue(searchBox); // Should contain the text (might have slight variations due to mistakes) expect(value.toLowerCase()).toContain('testing'); expect(value.toLowerCase()).toContain('behavior'); } finally { await page.close(); await context.close(); } }); }); test.describe('Google Alert validation examples', () => { test('should validate a simple Google Alert query', async ({ browser }) => { const context = await getHumanizedContext(browser); const page = await context.newPage(); try { // Test query for MacBook repair in Toronto const query = '"macbook repair" Toronto'; await page.goto('https://www.google.com'); await randomDelay(1000, 2000); // Perform search const searchBox = 'textarea[name="q"], input[name="q"]'; await humanClick(page, searchBox); await humanType(page, searchBox, query); await randomDelay(500, 1000); await page.keyboard.press('Enter'); // Wait for results await page.waitForLoadState('networkidle'); await randomDelay(1500, 2500); // Check if we got results const resultCount = await page.locator('div.g').count(); expect(resultCount).toBeGreaterThan(0); // Scroll through results naturally await humanScroll(page, { scrollCount: 2 }); // Simulate reading await simulateReading(page, 2000); console.log(`✅ Query "${query}" returned ${resultCount} results`); } finally { await page.close(); await context.close(); } }); test('should validate Reddit-specific query', async ({ browser }) => { const context = await getHumanizedContext(browser); const page = await context.newPage(); try { // Reddit-specific query const query = 'site:reddit.com/r/toronto "laptop repair"'; await page.goto('https://www.google.com'); await randomDelay(1000, 2000); // Perform search with human behavior const searchBox = 'textarea[name="q"], input[name="q"]'; await humanClick(page, searchBox); await humanType(page, searchBox, query, { mistakes: 0.03 }); await randomDelay(500, 1200); await page.keyboard.press('Enter'); // Wait and analyze await page.waitForLoadState('networkidle'); await randomDelay(2000, 3000); // Natural scrolling await humanScroll(page, { scrollCount: 2, minScroll: 200, maxScroll: 500 }); // Extract results const results = await page.evaluate(() => { const items = document.querySelectorAll('div.g'); return Array.from(items).length; }); console.log(`✅ Reddit query returned ${results} results`); expect(results).toBeGreaterThanOrEqual(0); } finally { await page.close(); await context.close(); } }); });