Path: blob/main/plugins/default-human-emulator/test/emulator.test.ts
1031 views
import { IInteractionStep, InteractionCommand } from '@secret-agent/interfaces/IInteractions';1import IViewport from '@secret-agent/interfaces/IViewport';2import Log from '@secret-agent/commons/Logger';3import { IBoundLog } from '@secret-agent/interfaces/ILog';4import ICorePluginCreateOptions from '@secret-agent/interfaces/ICorePluginCreateOptions';5import HumanEmulator, { isVisible } from '../index';67const { log } = Log(module);89beforeAll(() => {10HumanEmulator.maxDelayBetweenInteractions = 0;11HumanEmulator.maxScrollDelayMillis = 0;12});1314describe('typing', () => {15test('should spread out characters based on a wpm range', async () => {16HumanEmulator.wordsPerMinuteRange = [34, 34];17const humanEmulator = new HumanEmulator({ logger: log as IBoundLog } as ICorePluginCreateOptions);18const groups = [19[20{21command: InteractionCommand.type,22keyboardCommands: [{ string: 'Test typing sentence' }],23},24],25];26// @ts-ignore27const millisPerCharacter = humanEmulator.calculateMillisPerChar(groups);28expect(millisPerCharacter).toBe(353);2930let count = 0;31let totalMillis = 0;32await humanEmulator.playInteractions(33groups,34async interactionStep => {35expect(interactionStep.keyboardKeyupDelay).toBeGreaterThanOrEqual(10);36expect(interactionStep.keyboardKeyupDelay).toBeLessThanOrEqual(60);3738expect(interactionStep.keyboardDelayBetween).toBeGreaterThanOrEqual(353 - 60 - 353 / 2);39totalMillis += interactionStep.keyboardDelayBetween + interactionStep.keyboardKeyupDelay;40count += 1;41return null;42},43null,44);45const chars = 'Test typing sentence'.length;46expect(count).toBe(chars);47const charsPerSecond = totalMillis / 1000 / chars;48const charsPerMinute = 60 / charsPerSecond;49const wpm = Math.round(charsPerMinute / 5);50// should be close to 34 wpm51expect(Math.abs(34 - wpm)).toBeLessThanOrEqual(10);52});53});5455describe('deltaToVisible', () => {56test('should calculate deltas correctly', async () => {57expect(isVisible(20, 50, 100)).toBe(true);58// 85 + 25 is 110. Need to scroll +1059expect(isVisible(85, 50, 100)).toBe(false);60// -30 + 25 is -5. Need to scroll up -561expect(isVisible(-30, 50, 100)).toBe(false);62});6364test('should work to find center coordinates', async () => {65expect(isVisible(20, 100, 100)).toBe(true);66expect(isVisible(85, 100, 100)).toBe(false);67expect(isVisible(150, 100, 100)).toBe(false);68expect(isVisible(-30, 100, 100)).toBe(true);69expect(isVisible(-51, 100, 100)).toBe(false);70});71});7273describe('move', () => {74test('should break a move into a series of moves', async () => {75const humanEmulator = new HumanEmulator({ logger: log as IBoundLog } as ICorePluginCreateOptions);76const commands = [];77// @ts-ignore78await humanEmulator.scroll(79{80command: 'move',81mousePosition: [['document', 'querySelector', 'x']],82},83async step => {84commands.push(step);85},86{87mousePosition: { x: 25, y: 25 },88viewport: {89height: 600,90width: 800,91} as IViewport,92async lookupBoundingRect() {93return {94elementTag: 'div',95height: 10,96width: 100,97x: 0,98y: 800,99};100},101scrollOffset: Promise.resolve({ x: 0, y: 0 }),102logger: log,103createMouseupTrigger() {104return Promise.resolve({105didTrigger: () => Promise.resolve({ didClickLocation: true } as any),106});107},108createMouseoverTrigger() {109return Promise.resolve({110didTrigger: () => Promise.resolve(true),111});112},113},114);115116expect(commands.length).toBeGreaterThan(2);117});118});119120describe('scroll', () => {121test('should break a scroll into a curve', async () => {122const humanEmulator = new HumanEmulator({ logger: log as IBoundLog } as ICorePluginCreateOptions);123const commands = [];124// @ts-ignore125await humanEmulator.scroll(126{127command: 'scroll',128mousePosition: [['document', 'querySelector', 'x']],129},130async step => {131commands.push(step);132},133{134mousePosition: { x: 25, y: 25 },135viewport: {136height: 600,137width: 800,138} as IViewport,139async lookupBoundingRect() {140return {141elementTag: 'div',142height: 10,143width: 100,144x: 0,145y: 800,146};147},148scrollOffset: Promise.resolve({ x: 0, y: 0 }),149logger: log,150createMouseupTrigger() {151return Promise.resolve({152didTrigger: () => Promise.resolve({ didClickLocation: true } as any),153});154},155createMouseoverTrigger() {156return Promise.resolve({157didTrigger: () => Promise.resolve(true),158});159},160},161);162163expect(commands.length).toBeGreaterThan(1);164});165166test('should not scroll if over half in screen', async () => {167const humanEmulator = new HumanEmulator({ logger: log as IBoundLog } as ICorePluginCreateOptions);168const commands = [];169// @ts-ignore170await humanEmulator.scroll(171{172command: 'scroll',173mousePosition: [['document', 'querySelector', 'x']],174},175async step => {176commands.push(step);177},178{179mousePosition: { x: 25, y: 25 },180viewport: {181height: 600,182width: 800,183} as IViewport,184async lookupBoundingRect() {185return {186elementTag: 'div',187height: 200,188width: 100,189x: 50,190y: 499,191};192},193scrollOffset: Promise.resolve({ x: 0, y: 0 }),194logger: log,195createMouseupTrigger() {196return Promise.resolve({197didTrigger: () => Promise.resolve({ didClickLocation: true } as any),198});199},200createMouseoverTrigger() {201return Promise.resolve({202didTrigger: () => Promise.resolve(true),203});204},205},206);207208expect(commands).toHaveLength(0);209});210211test('should not exceed max pixels per scroll', async () => {212const humanEmulator = new HumanEmulator({ logger: log as IBoundLog } as ICorePluginCreateOptions);213const commands: IInteractionStep[] = [];214// @ts-ignore215await humanEmulator.scroll(216{217command: 'scroll',218mousePosition: [['document', 'querySelector', 'x']],219},220async step => {221commands.push(step);222},223{224mousePosition: { x: 25, y: 25 },225viewport: {226height: 600,227width: 800,228} as IViewport,229async lookupBoundingRect() {230return {231elementTag: 'div',232height: 200,233width: 100,234x: 50,235y: 50000,236};237},238scrollOffset: Promise.resolve({ x: 0, y: 0 }),239logger: log,240createMouseupTrigger() {241return Promise.resolve({242didTrigger: () => Promise.resolve({ didClickLocation: true } as any),243});244},245createMouseoverTrigger() {246return Promise.resolve({247didTrigger: () => Promise.resolve(true),248});249},250},251);252253expect(commands.length).toBeGreaterThan(2);254255const scrolls = commands.filter(x => x.command === 'scroll');256for (let i = 0; i < scrolls.length; i += 1) {257const current = scrolls[i];258const next = scrolls[i + 1];259if (current && next) {260const diff = Math.round(261Math.abs((next.mousePosition[1] as number) - (current.mousePosition[1] as number)),262);263expect(diff).toBeLessThanOrEqual(500);264}265}266});267});268269270