// @vitest-environment node
import {expect,it} from 'vitest'
import {randomUUID} from 'node:crypto'
import {mkdtemp,realpath,rm} from 'node:fs/promises'
import {tmpdir} from 'node:os'
import {join} from 'node:path'
import {chromium,type Page} from 'playwright'
import {BrowserRuntime,type BrowserScope,type BrowserAction} from '../../src/runner/browser/runtime.js'
// Real Chromium, isolated profile and synthetic page. No external website or account.
it.runIf(process.env.YAOYAO_BROWSER_SMOKE==='1')('real Chromium: sliders, text selection, HTML drop and live holds with cancellation',async()=>{
const root=await realpath(await mkdtemp(join(tmpdir(),'yaoyao-browser-drag-')))
const scope:BrowserScope={ownerKey:'drag-test',environmentId:'drag-bot',profile:'temporary'}
let page!:Page
const runtime=new BrowserRuntime({root,enabled:true,launcher:{launchPersistentContext:async(directory,options)=>{
const context=await chromium.launchPersistentContext(directory,options);page=context.pages()[0]!
await page.setContent(`
Drag this sentence to select the text.
Drag me
Drop here
`)
return context
}}})
let generation=0
const execute=(action:BrowserAction)=>runtime.execute(scope,{generation,operationId:randomUUID(),action})
try{
generation=(await runtime.open(scope)).generation
const slider=(await page.locator('input').boundingBox())!,y=slider.y+slider.height/2
await execute({kind:'drag',fromX:slider.x+8,fromY:y,toX:slider.x+390,toY:y})
expect(Number(await page.locator('input').inputValue())).toBeGreaterThan(95)
const text=(await page.locator('p').boundingBox())!
await execute({kind:'drag',fromX:text.x+1,fromY:text.y+10,toX:text.x+240,toY:text.y+10})
expect(await page.evaluate(()=>getSelection()?.toString())).toContain('Drag this sentence')
const source=(await page.locator('#source').boundingBox())!,target=(await page.locator('#target').boundingBox())!
const start={x:source.x+40,y:source.y+40},end={x:target.x+40,y:target.y+40}
await execute({kind:'drag',fromX:start.x,fromY:start.y,toX:end.x,toY:end.y})
expect(await page.locator('#drops').innerText()).toBe('1')
const gestureId=randomUUID()
await execute({kind:'pointer',gestureId,phase:'start',x:slider.x+390,y})
const releases=await page.evaluate(()=>(window as any).releases)
await execute({kind:'pointer',gestureId,phase:'move',x:slider.x+200,y})
// This observation happens while the button is still held, before pointer end.
expect(Number(await page.locator('input').inputValue())).toBeGreaterThan(45)
expect(Number(await page.locator('input').inputValue())).toBeLessThan(55)
expect(await page.evaluate(()=>(window as any).buttons)).toBe(1)
expect(await page.evaluate(()=>(window as any).releases)).toBe(releases)
await execute({kind:'screenshot'})
await execute({kind:'pointer',gestureId,phase:'end',x:slider.x+300,y})
expect(Number(await page.locator('input').inputValue())).toBeGreaterThan(70)
expect(await page.evaluate(()=>(window as any).releases)).toBe(releases+1)
const dropId=randomUUID()
await execute({kind:'pointer',gestureId:dropId,phase:'start',...start})
await execute({kind:'pointer',gestureId:dropId,phase:'move',...end})
await execute({kind:'pointer',gestureId:dropId,phase:'end',...end})
expect(await page.locator('#drops').innerText()).toBe('2')
const cancelId=randomUUID()
await execute({kind:'pointer',gestureId:cancelId,phase:'start',...start})
await execute({kind:'pointer',gestureId:cancelId,phase:'move',...end})
await execute({kind:'pointer',gestureId:cancelId,phase:'cancel',...end})
expect(await page.locator('#drops').innerText()).toBe('2')
await page.mouse.move(100,700)
expect(await page.evaluate(()=>(window as any).buttons)).toBe(0)
}finally{await runtime.shutdown();await rm(root,{recursive:true,force:true})}
},30000)