rss-feedmonitor/tests/human-behavior.test.js

319 lines
9.1 KiB
JavaScript

/**
* 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();
}
});
});