選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 
 

115 行
6.4 KiB

  1. import fs from 'node:fs'
  2. import path from 'node:path'
  3. import { createRequire } from 'node:module'
  4. import { fileURLToPath } from 'node:url'
  5. import assert from 'node:assert/strict'
  6. import { login } from './role-permissions-live.mjs'
  7. const { chromium, expect } = createRequire(new URL('../package.json', import.meta.url))('@playwright/test')
  8. const report = fileURLToPath(new URL('../reports/guide-style-20260909/', import.meta.url))
  9. fs.mkdirSync(report, { recursive:true })
  10. const browser = await chromium.launch({ channel:'msedge', headless:true, args:['--enable-unsafe-swiftshader'] })
  11. const checks = [], errors = []
  12. const session = await login('root')
  13. const context = await browser.newContext({ viewport:{ width:1920, height:911 } })
  14. await context.addInitScript(({ accessToken, refreshToken }) => {
  15. sessionStorage.setItem('unreal-tran:web:access-token:v1', accessToken)
  16. sessionStorage.setItem('unreal-tran:web:refresh-token:v1', refreshToken)
  17. }, session)
  18. const page = await context.newPage()
  19. page.on('pageerror', error => errors.push(error.message))
  20. async function shot(name) {
  21. const overflow = await page.locator('.legacy-guide-page').evaluate(el => el.scrollWidth > el.clientWidth + 2)
  22. assert.equal(overflow, false, `${name}: page has no horizontal overflow`)
  23. await page.screenshot({ path:path.join(report, `${name}.png`), animations:'disabled' })
  24. checks.push({ name, result:'PASS', screenshot:`${name}.png` })
  25. }
  26. async function theme(mode) {
  27. await page.evaluate(async mode => (await import('/src/stores/preferences.ts')).usePreferencesStore().setThemeMode(mode), mode)
  28. }
  29. try {
  30. await page.goto('http://127.0.0.1:6180/content/ofd')
  31. await expect(page.locator('.guide-project-list')).toBeVisible({ timeout:60000 })
  32. await theme('military')
  33. // Fixtures exist only in this disposable browser's local guide repository.
  34. await page.evaluate(async () => {
  35. const { legacyGuideContentStore } = await import('/src/features/guide-legacy/runtime.ts')
  36. for (let i=1;i<=12;i++) legacyGuideContentStore.createOFDProject({ id:`STYLE-${i}`, code:`STYLE-${String(i).padStart(3,'0')}`, title:`液压系统检查作业指导书 · 样式验证 ${i}`, author:'样式验证' })
  37. })
  38. await expect(page.locator('.guide-project-title')).toHaveCount(10)
  39. console.log('List loaded', await page.locator('.guide-project-title').count())
  40. await shot('01-list')
  41. const count = await page.locator('.guide-project-title').count()
  42. await page.getByRole('textbox', { name:'搜索指导书', exact:true }).fill('NO-MATCH-GUIDE-STYLE')
  43. assert.equal(await page.locator('.guide-project-title').count(), count, 'Search waits for explicit submission')
  44. await page.locator('.guide-project-list').getByRole('button', { name:'搜索', exact:true }).click()
  45. await expect(page.locator('.guide-project-title')).toHaveCount(0)
  46. await page.getByRole('button', { name:'重置', exact:true }).click()
  47. await expect(page.locator('.guide-project-title')).toHaveCount(count)
  48. await page.locator('.system-pagination .btn-next').click()
  49. await expect(page.locator('.guide-project-title')).toHaveCount(2)
  50. await page.locator('.system-pagination .btn-prev').click()
  51. await expect(page.locator('.guide-project-title')).toHaveCount(10)
  52. if (count) {
  53. await page.locator('.guide-project-actions').first().getByRole('button', { name:'更多' }).click()
  54. await expect(page.getByRole('menuitem', { name:'项目详情', exact:true })).toBeVisible()
  55. await shot('02-list-actions')
  56. await page.getByRole('menuitem', { name:'项目详情', exact:true }).click()
  57. await expect(page.getByRole('button', { name:'关闭项目详情' })).toBeVisible()
  58. await page.getByRole('button', { name:'关闭项目详情' }).click()
  59. await page.locator('.guide-project-actions').first().getByRole('button', { name:'进入编制', exact:true }).click()
  60. await expect(page.locator('.ofd-view-editor')).toBeVisible({ timeout:60000 })
  61. await shot('03-editor')
  62. await theme('dark')
  63. await shot('03-editor-dark')
  64. await theme('military')
  65. await page.locator('.ofd-top-actions [data-action="open-preview"]').click()
  66. await expect(page.locator('.ofd-workspace-dialog.preview')).toBeVisible()
  67. await shot('03-guide-preview')
  68. console.log('Editor loaded', page.url())
  69. }
  70. await page.goto('http://127.0.0.1:6180/content/ofd/templates')
  71. await expect(page.locator('.guide-tpl-card')).toHaveCount(4, { timeout:30000 })
  72. await page.locator('[data-guide-tpl-action="select"]').nth(1).click()
  73. await expect(page.locator('.guide-tpl-card').nth(1)).toHaveClass(/is-active/)
  74. await shot('04-templates')
  75. await page.locator('.guide-tpl-card').nth(1).getByRole('button', { name:'预览', exact:true }).click()
  76. await expect(page.locator('.guide-tpl-modal')).toBeVisible()
  77. await shot('05-template-preview')
  78. await page.goto('http://127.0.0.1:6180/content/ofd/api')
  79. await expect(page.locator('.ofd-api-layout')).toBeVisible({ timeout:30000 })
  80. await shot('06-api')
  81. await page.getByRole('button', { name:'执行调用', exact:true }).click()
  82. await expect(page.locator('.ofd-api-result')).toBeVisible()
  83. await expect(page.locator('.ofd-api-result header b')).toHaveText('200')
  84. await shot('07-api-result')
  85. for (const mode of ['technology','graphite','dark']) {
  86. await theme(mode)
  87. await shot(`08-api-${mode}`)
  88. }
  89. await page.setViewportSize({ width:1366, height:768 })
  90. await theme('military')
  91. await shot('09-api-laptop')
  92. await page.goto('http://127.0.0.1:6180/content/ofd/templates')
  93. await expect(page.locator('.guide-tpl-card')).toHaveCount(4)
  94. await shot('10-templates-laptop')
  95. await theme('dark')
  96. await shot('11-templates-dark')
  97. await page.goto('http://127.0.0.1:6180/content/ofd')
  98. await expect(page.locator('.guide-project-list')).toBeVisible()
  99. await shot('12-list-dark')
  100. await theme('military')
  101. await page.getByRole('button', { name:'新建指导书', exact:true }).click()
  102. await expect(page.locator('.ofd-app')).toBeVisible()
  103. await shot('13-create-wizard')
  104. assert.equal((await context.request.get('http://192.168.31.168:6180/')).status(),200)
  105. assert.deepEqual(errors, [], 'No unhandled browser exceptions')
  106. checks.push({ name:'搜索/重置、详情、编制入口、模板选择/预览、GET 接口自检、主题切换、局域网入口', result:'PASS' })
  107. } catch(error) {
  108. await page.screenshot({ path:path.join(report,'failure.png') }).catch(()=>{})
  109. console.error('Browser errors:',errors)
  110. throw error
  111. } finally {
  112. fs.writeFileSync(path.join(report,'results.json'), JSON.stringify({ checks, errors },null,2))
  113. await browser.close()
  114. }