import {test, expect} from '@playwright/test' import {buildTrafficFromSamples} from '../../backend/src/services/traffic-rate' for (const mode of ['servers','flows'] as const) for (const minutes of [5,15]) { test(`${mode}: ${minutes} минут рисуются линией`, async ({page}) => { const end=Date.now(), name='Короткая история' const history=(span:number)=>buildTrafficFromSamples(Array.from({length:span*2+1},(_,i)=>({ interfaceName:'ether1',sampledAt:new Date(end-span*60000+i*30000).toISOString(), rxBytes:i*3750000,txBytes:i*1875000,rxBps:0,txBps:0,running:true,disabled:false, })),end-span*60000,end,undefined,undefined,true) await page.route('**/health',r=>r.fulfill({json:{ok:true}})) await page.route('**/api/**',r=>{ const url=new URL(r.request().url()),path=url.pathname,span=url.searchParams.get('range')==='5m'?5:url.searchParams.get('range')==='15m'?15:60 const built=history(span),server={id:'1',name,site:'TEST',country:'RU',status:'online',...built,rxTotal:1,txTotal:1,volumeUnit:'GiB'} const card={id:'1',name,subtitle:'',site:'TEST',country:'RU',status:'online',rxNow:1,txNow:0,sessions:1,bytes:60000,rxSeries:[1,2,1],txSeries:[0,0,0]} const analytics={bpsNow:1000000,bytes:60000,packets:10,conversations:1,uniqueSrc:1,uniqueDst:1,topProto:'TCP',rxSeries:Array.from({length:span},(_,i)=>1+i%3),txSeries:Array(span).fill(0),applications:[],protocols:[],sources:[],destinations:[],interfaces:[],conversationsList:[],ifaces:[],live:false} if(path.endsWith('/live'))return r.fulfill({status:503,json:{error:'Live выключен в проверке истории'}}) const json=path==='/api/auth/config'?{required:false}:path==='/api/traffic/servers'?{servers:[server]}: path==='/api/traffic/servers/1'?{server}:path==='/api/traffic/flow/exporters'?{exporters:[card]}: path==='/api/traffic/flow/analytics'?analytics:path==='/api/traffic/flow/clients'?{clients:[]}: path==='/api/traffic/flows'?{exportersOnline:1,bytesPerMin:1,uniqueSrc:1,uniqueDst:1,topProto:'TCP',talkers:[],listenerBound:true}: path==='/api/traffic/users'?{users:[]}:path.endsWith('/interfaces')||path.endsWith('/bound-interfaces')?{interfaces:[]}: path==='/api/servers'?[]:{} return r.fulfill({json}) }) await page.goto('/traffic') if(mode==='flows')await page.getByRole('group',{name:'Разделы трафика'}).getByRole('button',{name:'Потоки',exact:true}).click() await page.getByRole('button',{name:`${minutes}м`,exact:true}).click() const chart=page.getByRole('region',{name:'История RX/TX'}) await expect(chart).toBeVisible() const curves=chart.locator('path.recharts-line-curve') await expect(curves).toHaveCount(2) await expect.poll(async()=>((await curves.first().getAttribute('d'))?.match(/[CL]/g)||[]).length).toBeGreaterThan(2) await expect.poll(()=>curves.first().evaluate(el=>(el as SVGGraphicsElement).getBBox().width/el.closest('[role="region"]')!.clientWidth)).toBeGreaterThan(0.7) await expect(chart.locator('[data-isolated-direction]')).toHaveCount(0) await page.screenshot({path:`tmp/netflow-agent-stand/traffic-short-${mode}-${minutes}.png`,fullPage:true}) }) }