您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

71 行
6.1 KiB

  1. import fs from 'node:fs'
  2. import path from 'node:path'
  3. import {chromium,expect} from '@playwright/test'
  4. import {login,call} from './role-permissions-live.mjs'
  5. const report=path.resolve('reports/guide-formal-20260910'), fixture=JSON.parse(fs.readFileSync('../../.codex-tmp/guide-formal/fixture.json'))
  6. const session=await login('root'), token=session.accessToken, checks=[],errors=[]
  7. const browser=await chromium.launch({channel:'msedge',headless:true,args:['--enable-unsafe-swiftshader']})
  8. const context=await browser.newContext({viewport:{width:1920,height:1080}})
  9. await context.addInitScript(s=>{sessionStorage.setItem('unreal-tran:web:access-token:v1',s.accessToken);sessionStorage.setItem('unreal-tran:web:refresh-token:v1',s.refreshToken)},session)
  10. const page=await context.newPage();page.on('pageerror',e=>errors.push(e.message))
  11. const check=(name,pass,detail='')=>{checks.push({name,pass,detail});console.log(pass?'PASS':'FAIL',name);if(!pass)process.exitCode=1}
  12. const shot=name=>page.screenshot({path:path.join(report,name+'.png')})
  13. const openReader=async()=>{
  14. await page.goto('http://127.0.0.1:6180/teaching/guides')
  15. await page.getByPlaceholder('搜索指导书名称或编码').fill('正式闭环-狐狸与卡车指导书-20260910')
  16. await page.getByPlaceholder('搜索指导书名称或编码').press('Enter')
  17. await expect(page.locator('.guide-card-v2')).toHaveCount(1)
  18. await page.locator('.guide-card-v2 button').first().click()
  19. await expect(page.locator('.legacy-published-reader .ofd-preview-pager')).toBeVisible({timeout:60000})
  20. }
  21. try{
  22. const state=(await call(`tran/v1/teaching/guides/${fixture.id}/reader-state`,token)).data
  23. await call(`tran/v1/teaching/guides/${fixture.id}/reader-state`,token,{...state,pageId:'page:2',pageIndex:2,pageCount:4,favorite:true,notes:[{id:'final-1',pageId:'page:1',text:'定位核对记录'},{id:'final-2',pageId:'page:2',text:'编辑与删除测试记录'}]},'PUT')
  24. await openReader()
  25. await expect(page.locator('.legacy-published-reader .ofd-preview-pager')).toContainText('3 / 4')
  26. check('重新打开恢复上次第三页阅读位置',true)
  27. await page.getByRole('button',{name:/笔记 2/}).click()
  28. const note=page.locator('.reader-note').last()
  29. await note.getByRole('button',{name:'编辑',exact:true}).click()
  30. await page.getByPlaceholder('记录当前页的阅读笔记').fill('已修改:复查牛奶卡车后确认记录。')
  31. const edited=page.waitForResponse(r=>r.url().endsWith('/reader-state')&&r.request().method()==='PUT')
  32. await page.getByRole('button',{name:'保存修改',exact:true}).click();check('笔记编辑保存成功',(await edited).ok())
  33. await expect(note).toContainText('已修改')
  34. const removed=page.waitForResponse(r=>r.url().endsWith('/reader-state')&&r.request().method()==='PUT')
  35. await note.getByRole('button',{name:'删除',exact:true}).click();check('笔记删除成功',(await removed).ok())
  36. await expect(page.locator('.reader-note')).toHaveCount(1)
  37. await page.locator('.el-drawer__close-btn:visible').click()
  38. const unfavorite=page.waitForResponse(r=>r.url().endsWith('/reader-state')&&r.request().method()==='PUT')
  39. await page.getByRole('button',{name:'取消收藏',exact:true}).click();check('取消收藏写回服务器',(await unfavorite).ok())
  40. await page.locator('.legacy-published-reader [data-action="preview-tab"][data-tab="interactive"]').click()
  41. await page.locator('.legacy-published-reader [data-action="interactive-next"]').click()
  42. await page.locator('.legacy-published-reader canvas').first().scrollIntoViewIfNeeded()
  43. await page.waitForTimeout(3000);await shot('11-reader-truck')
  44. const position=await call(`tran/v1/teaching/guides/${fixture.id}/reader-state`,token)
  45. check('动态阅读同步第四页和百分百页进度',position.data?.pageIndex===3&&position.data?.progress===100)
  46. await expect(page.locator('.legacy-published-reader [data-action="interactive-step"]').first()).toBeEnabled()
  47. await expect(page.locator('.legacy-published-reader [data-model-clip-select]')).toBeEnabled()
  48. check('教学只读模式允许目录定位和选择动画',true)
  49. check('教学动态版式切换卡车步骤',await page.locator('.legacy-published-reader').textContent().then(t=>t.includes('牛奶卡车检查')))
  50. if(await page.getByRole('button',{name:'标记阅读完成',exact:true}).count())await page.getByRole('button',{name:'标记阅读完成',exact:true}).click()
  51. await expect(page.getByRole('button',{name:'已完成阅读',exact:true})).toBeDisabled()
  52. await shot('12-reading-completed');check('浏览器完成阅读并更新状态',true)
  53. await page.goto('http://127.0.0.1:6180/content/ofd/api')
  54. await page.locator('.guide-http-page nav button').filter({hasText:'保存笔记、收藏与进度'}).click()
  55. await page.locator('.guide-http-page .el-select').first().click()
  56. await page.getByRole('option').filter({hasText:'正式闭环-狐狸与卡车指导书-20260910'}).click()
  57. await page.getByRole('button',{name:'载入当前工程版本参数',exact:true}).click()
  58. await expect(page.getByRole('textbox',{name:'请求 JSON'})).toHaveValue(/versionId/)
  59. const saved=page.waitForResponse(r=>r.url().endsWith('/reader-state')&&r.request().method()==='PUT')
  60. await page.getByRole('button',{name:'执行调用',exact:true}).click();check('HTTP 面板实际 PUT 阅读记录',(await saved).ok())
  61. const conflict=page.waitForResponse(r=>r.url().endsWith('/reader-state')&&r.request().method()==='PUT')
  62. await page.getByRole('button',{name:'执行调用',exact:true}).click();check('HTTP 面板旧版本返回 409',(await conflict).status()===409)
  63. await shot('13-http-conflict')
  64. const method=await call(`tran/v1/teaching/guides/${fixture.id}/reading/start`,token,{},'POST')
  65. check('错误 HTTP 方法明确返回 405',method.status===405)
  66. await page.goto('http://127.0.0.1:6180/content/ofd/templates')
  67. await expect(page.locator('.template-card').first()).toBeVisible({timeout:30000})
  68. await shot('14-formal-templates');check('正式模板库可用',true)
  69. }catch(e){check('最终浏览器回归',false,e.message);await shot('final-failure')}
  70. finally{check('无浏览器脚本异常',errors.length===0,errors.join('\n'));fs.writeFileSync(path.join(report,'final.json'),JSON.stringify({checks,errors},null,2));await browser.close()}