Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 
 
 

76 rindas
5.0 KiB

  1. import fs from 'node:fs'
  2. import path from 'node:path'
  3. import assert from 'node:assert/strict'
  4. import { createRequire } from 'node:module'
  5. import { fileURLToPath } from 'node:url'
  6. import { login, call } from './role-permissions-live.mjs'
  7. const require = createRequire(new URL('../package.json', import.meta.url))
  8. const { chromium, expect } = require('@playwright/test')
  9. const report = fileURLToPath(new URL('../reports/advanced-drag-layout-20260909/', import.meta.url))
  10. fs.mkdirSync(report, { recursive: true })
  11. const session = await login('root')
  12. const project = (await call('tran/v1/content/projects?type=TRAINING&size=100', session.accessToken)).data.records.find(row => row.name.includes('APE2E-数字人讲解-狐狸'))
  13. assert.ok(project)
  14. const browser = await chromium.launch({ channel: 'msedge', headless: true, args: ['--enable-unsafe-swiftshader'] })
  15. let page
  16. const checks = []
  17. try {
  18. const context = await browser.newContext({ viewport: { width: 1920, height: 911 } })
  19. await context.addInitScript(({ accessToken, refreshToken }) => {
  20. sessionStorage.setItem('unreal-tran:web:access-token:v1', accessToken)
  21. sessionStorage.setItem('unreal-tran:web:refresh-token:v1', refreshToken)
  22. localStorage.setItem('unreal-tran:web:preferences:v1', JSON.stringify({ themeMode: 'military' }))
  23. }, session)
  24. page = await context.newPage()
  25. await page.goto(`http://127.0.0.1:6180/content/training-projects/${project.id}/legacy`)
  26. await page.getByRole('radio', { name: '高级编排', exact: true }).click({ timeout: 60000 })
  27. const canvas = page.locator('[data-role="flow-canvas"]')
  28. const node = page.locator('[data-flow-node="flow-start"]')
  29. const head = node.locator('.tfa-node-head')
  30. await head.scrollIntoViewIfNeeded()
  31. const initial = await node.evaluate(el => ({ x: parseFloat(el.style.left), y: parseFloat(el.style.top) }))
  32. const box = await head.boundingBox(), area = await canvas.boundingBox()
  33. await page.mouse.move(box.x + 45, box.y + 22)
  34. await page.mouse.down()
  35. const pointerY = area.y + area.height - 100
  36. await page.mouse.move(box.x + 45, pointerY, { steps: 12 })
  37. const before = await node.evaluate(el => parseFloat(el.style.top))
  38. const scrollDelta = await canvas.evaluate(el => { const old = el.scrollTop; el.scrollTop += 180; return el.scrollTop - old })
  39. assert.ok(scrollDelta > 80)
  40. await page.mouse.move(box.x + 45, pointerY + 5, { steps: 2 })
  41. const after = await node.evaluate(el => parseFloat(el.style.top))
  42. assert.ok(Math.abs(after - before - scrollDelta - 5) < 3, 'Node follows pointer in scrolled coordinates')
  43. const oldLimit = await canvas.evaluate(el => el.clientHeight - 110)
  44. assert.ok(after > oldLimit + 80, 'Node reaches grid below the former viewport limit')
  45. await page.mouse.up()
  46. checks.push({ name: '拖入下方网格,拖动中滚动不跳位', result: 'PASS', before, after, scrollDelta, formerLimit: oldLimit })
  47. const scrollBefore = await canvas.evaluate(el => el.scrollTop)
  48. await head.click()
  49. await expect.poll(() => canvas.evaluate(el => el.scrollTop)).toBe(scrollBefore)
  50. await expect.poll(() => node.evaluate(el => parseFloat(el.style.top))).toBe(after)
  51. await page.screenshot({ path: path.join(report, '01-lower-grid.png'), animations: 'disabled' })
  52. checks.push({ name: '选择节点后保留画布滚动位置', result: 'PASS' })
  53. await page.setViewportSize({ width: 1366, height: 768 })
  54. const last = page.locator('.tfa-node').last(), lastHead = last.locator('.tfa-node-head')
  55. await lastHead.scrollIntoViewIfNeeded()
  56. const previous = await last.evaluate(el => ({ x: parseFloat(el.style.left), y: parseFloat(el.style.top) }))
  57. const lastBox = await lastHead.boundingBox()
  58. await page.mouse.move(lastBox.x + 45, lastBox.y + 22)
  59. await page.mouse.down()
  60. await page.mouse.move(lastBox.x + 55, lastBox.y + 32, { steps: 4 })
  61. await page.mouse.up()
  62. const next = await last.evaluate(el => ({ x: parseFloat(el.style.left), y: parseFloat(el.style.top) }))
  63. assert.ok(Math.abs(next.x - previous.x - 10) < 2 && Math.abs(next.y - previous.y - 10) < 2, 'Small drag after horizontal scroll must not jump to viewport limit')
  64. await page.screenshot({ path: path.join(report, '02-horizontal-scroll.png'), animations: 'disabled' })
  65. checks.push({ name: '窄窗口横向滚动后拖动不跳位', result: 'PASS', previous, next })
  66. await page.getByRole('radio', { name: '基础编排', exact: true }).click()
  67. await page.getByRole('radio', { name: '高级编排', exact: true }).click()
  68. assert.equal(await node.evaluate(el => parseFloat(el.style.top)), after)
  69. checks.push({ name: '切换编排模式保留节点坐标', result: 'PASS' })
  70. fs.writeFileSync(path.join(report, 'results.json'), JSON.stringify({ passed: true, projectId: project.id, accountType: '内部维护', initial, checks, dataChanges: '仅调整已有测试工程的浏览器草稿,未点击保存或发布。' }, null, 2))
  71. console.log('Advanced drag layout checks passed')
  72. } catch (error) {
  73. if (page) await page.screenshot({ path: path.join(report, 'failure.png'), animations: 'disabled' }).catch(() => {})
  74. throw error
  75. } finally { await browser.close() }