242 lines
11 KiB
JavaScript
242 lines
11 KiB
JavaScript
import assert from 'node:assert/strict'
|
|
import { chromium } from 'playwright'
|
|
const browser = await chromium.launch({ headless: true, channel: 'chrome' })
|
|
const context = await browser.newContext({ viewport: { width: 1440, height: 1000 } })
|
|
const page = await context.newPage()
|
|
page.setDefaultTimeout(20000)
|
|
page.on('console', (msg) => {
|
|
if (msg.type() === 'error') console.log('CONSOLE', msg.text())
|
|
})
|
|
page.on('requestfailed', (req) => console.log('REQUESTFAILED', req.url(), req.failure()))
|
|
const errors = []
|
|
page.on('pageerror', (error) => errors.push(error.message))
|
|
let sharedUsers = []
|
|
let uploads = 0
|
|
let lastUploadBody = ''
|
|
let lastParentId = ''
|
|
let deletes = 0
|
|
let mineDeleted = false
|
|
let failList = false
|
|
let folders = []
|
|
const makeRoot = (scope, name, children = []) => ({
|
|
id: `scope:${scope}`,
|
|
name,
|
|
scope,
|
|
folderId: '',
|
|
fullPath: `${name} / 全部文件`,
|
|
ownerId: '',
|
|
canManage: scope === 'mine',
|
|
count: 1,
|
|
children
|
|
})
|
|
const file = {
|
|
id: 'mine-1',
|
|
name: '产品资料.pdf',
|
|
folderId: '',
|
|
folderPath: '我的文档 / 根目录',
|
|
size: 1234,
|
|
contentType: 'application/pdf',
|
|
ownerId: 'fixture',
|
|
ownerName: '测试',
|
|
createTime: '2026-10-26 10:00:00',
|
|
updateTime: '2026-10-26 10:00:00',
|
|
canManage: true,
|
|
shares: []
|
|
}
|
|
const sharedFile = {
|
|
...file,
|
|
id: 'shared-1',
|
|
name: '共享制度.pdf',
|
|
ownerId: 'other',
|
|
ownerName: '同事',
|
|
canManage: false,
|
|
shares: [{ id: 'fixture', name: '测试', deptName: '研发部' }]
|
|
}
|
|
await context.addInitScript(() => {
|
|
localStorage.setItem(
|
|
'sys-v3.0.2-user',
|
|
JSON.stringify({
|
|
isLogin: true,
|
|
accessToken: 'fixture',
|
|
info: { id: 'fixture', userId: 'fixture', userName: '测试', role: 'admin', roles: ['admin'] }
|
|
})
|
|
)
|
|
localStorage.setItem('sys-version', '3.0.2')
|
|
})
|
|
await context.route('**/api/**', async (route) => {
|
|
const req = route.request(),
|
|
url = new URL(req.url()),
|
|
path = url.pathname.slice(4)
|
|
if (!url.pathname.startsWith('/api/')) return route.continue()
|
|
const ok = (data) => route.fulfill({ json: { code: 200, data } })
|
|
if (path === '/web/auth/current-user')
|
|
return ok({
|
|
id: 'fixture',
|
|
userId: 'fixture',
|
|
userName: '测试',
|
|
role: 'admin',
|
|
roles: ['admin']
|
|
})
|
|
if (path === '/web/auth/menu-codes') return ok({ all: true, menuCodes: [] })
|
|
if (path === '/web/doclib/tree')
|
|
return ok({
|
|
nodes: [makeRoot('mine', '我的文档', folders), makeRoot('shared', '分享给我')],
|
|
isSuperAdmin: false,
|
|
maxUploadBytes: 100000
|
|
})
|
|
if (path === '/web/doclib/files') {
|
|
if (failList) return route.fulfill({ status: 400, json: { code: 400, message: '加载失败' } })
|
|
const row = url.searchParams.get('scope') === 'shared' ? sharedFile : file
|
|
const list =
|
|
!mineDeleted &&
|
|
(!url.searchParams.get('keyword') || row.name.includes(url.searchParams.get('keyword')))
|
|
? [row]
|
|
: []
|
|
return ok({ list, total: list.length })
|
|
}
|
|
if (path === '/web/doclib/users') return ok([{ id: 'other', name: '同事', deptName: '生产部' }])
|
|
if (path === '/web/doclib/files/batch-shares' && req.method() === 'POST') {
|
|
const body = req.postDataJSON()
|
|
sharedUsers = body.userIds
|
|
file.shares = sharedUsers.map((id) => ({ id, name: '同事', deptName: '生产部' }))
|
|
return ok([file])
|
|
}
|
|
if (path.endsWith('/shares')) {
|
|
sharedUsers = req.postDataJSON().userIds
|
|
file.shares = sharedUsers.map((id) => ({ id, name: '同事', deptName: '生产部' }))
|
|
return ok(file)
|
|
}
|
|
if (path === '/web/doclib/folders' && req.method() === 'POST') {
|
|
const body = req.postDataJSON()
|
|
lastParentId = body.parentId
|
|
const folder = {
|
|
id: `mine:f${folders.length + 1}`,
|
|
folderId: `f${folders.length + 1}`,
|
|
name: body.name,
|
|
fullPath: `我的文档 / ${body.name}`,
|
|
scope: 'mine',
|
|
ownerId: 'fixture',
|
|
canManage: true,
|
|
count: 0,
|
|
children: []
|
|
}
|
|
folders.push(folder)
|
|
return ok(folder)
|
|
}
|
|
if (path === '/web/doclib/upload') {
|
|
lastUploadBody = req.postData() || ''
|
|
uploads++
|
|
return ok({ ...file, id: `uploaded-${uploads}`, name: '上传测试.txt' })
|
|
}
|
|
if (path === '/web/doclib/files/batch-delete') {
|
|
mineDeleted = true
|
|
deletes++
|
|
return ok(null)
|
|
}
|
|
if (path.endsWith('/download'))
|
|
return route.fulfill({ body: 'fixture file', contentType: 'application/octet-stream' })
|
|
if (path === '/web/doclib/files/mine-1') return ok(file)
|
|
if (path === '/web/doclib/files/shared-1') return ok(sharedFile)
|
|
return ok(path.includes('favorites') || path.includes('upgrade-logs') ? [] : {})
|
|
})
|
|
try {
|
|
await page.goto('http://localhost:3006/#/doclib/enter')
|
|
await page.getByText('文档库', { exact: true }).first().click()
|
|
await page.locator('.doclib-page').waitFor()
|
|
assert.equal(context.pages().length, 1)
|
|
await page.locator('.doclib-file-text .el-link').filter({ hasText: '产品资料.pdf' }).waitFor()
|
|
assert.equal(await page.locator('.doclib-tree-node').count(), 2)
|
|
await page.locator('.doclib-tree-node').filter({ hasText: '分享给我' }).click()
|
|
await page.locator('.doclib-file-text .el-link').filter({ hasText: '共享制度.pdf' }).waitFor()
|
|
await page.locator('.el-table__body .el-checkbox').first().click()
|
|
assert.equal(await page.getByRole('button', { name: '设置分享', exact: true }).isDisabled(), true)
|
|
assert.equal(await page.getByRole('button', { name: '删除', exact: true }).isDisabled(), true)
|
|
assert.equal(await page.getByRole('button', { name: '下载', exact: true }).isEnabled(), true)
|
|
assert.equal(await page.getByRole('button', { name: '上传文档', exact: true }).count(), 0)
|
|
await page.locator('.doclib-file-text .el-link').filter({ hasText: '共享制度.pdf' }).click()
|
|
const detail = page.locator('.system-view-dialog:visible')
|
|
await detail.getByRole('button', { name: '下载文档', exact: true }).waitFor()
|
|
assert.equal(await detail.getByRole('button', { name: '设置分享', exact: true }).count(), 0)
|
|
const downloaded = page.waitForEvent('download')
|
|
await detail.getByRole('button', { name: '下载文档', exact: true }).click()
|
|
assert.equal((await downloaded).suggestedFilename(), '共享制度.pdf')
|
|
await detail.locator('.el-dialog__headerbtn').click()
|
|
await page.locator('.doclib-tree-node').filter({ hasText: '我的文档' }).click()
|
|
await page.locator('.doclib-file-text .el-link').filter({ hasText: '产品资料.pdf' }).waitFor()
|
|
assert.match(await page.locator('.doclib-selected').innerText(), /0/)
|
|
await page.locator('.el-table__body .el-checkbox').first().click()
|
|
await page.getByRole('button', { name: '设置分享', exact: true }).click()
|
|
const share = page.locator('.doclib-dialog:visible')
|
|
await share.getByRole('combobox').click()
|
|
await page.getByRole('option', { name: /同事/ }).click()
|
|
await share.getByRole('button', { name: '保存分享' }).click()
|
|
await share.waitFor({ state: 'hidden' })
|
|
assert.deepEqual(sharedUsers, ['other'])
|
|
await page.getByRole('button', { name: '新建文件夹', exact: true }).click()
|
|
const folder = page.locator('.doclib-dialog:visible')
|
|
await folder.getByPlaceholder('请输入文件夹名称').fill('测试目录')
|
|
await folder.getByRole('button', { name: '保存', exact: true }).click()
|
|
await page.locator('.doclib-tree-node').filter({ hasText: '测试目录' }).waitFor()
|
|
assert.equal(lastParentId, '')
|
|
await page.getByRole('button', { name: '新建文件夹', exact: true }).click()
|
|
await folder.getByPlaceholder('请输入文件夹名称').fill('子目录')
|
|
await folder.getByRole('combobox', { name: '上级文件夹', exact: true }).click()
|
|
await page.getByRole('option', { name: '测试目录', exact: true }).click()
|
|
await folder.getByRole('button', { name: '保存', exact: true }).click()
|
|
await page.locator('.doclib-tree-node').filter({ hasText: '子目录' }).waitFor()
|
|
assert.equal(lastParentId, 'f1')
|
|
await page.getByRole('button', { name: '上传文档', exact: true }).click()
|
|
const upload = page.locator('.doclib-dialog:visible')
|
|
await upload.getByRole('combobox', { name: '上传到', exact: true }).click()
|
|
await page.getByRole('option', { name: '测试目录', exact: true }).click()
|
|
await upload.locator('input[type=file]').setInputFiles([
|
|
{ name: '上传测试.txt', mimeType: 'text/plain', buffer: Buffer.from('上传测试') },
|
|
{ name: '空文件.txt', mimeType: 'text/plain', buffer: Buffer.from('') }
|
|
])
|
|
await upload.getByText('已上传', { exact: true }).waitFor()
|
|
await upload.getByText('不能上传空文件', { exact: true }).waitFor()
|
|
assert.equal(uploads, 1)
|
|
assert.match(lastUploadBody, /name="folderId"\r\n\r\nf1/)
|
|
assert.equal(
|
|
await upload.getByRole('combobox', { name: '上传到', exact: true }).isDisabled(),
|
|
true
|
|
)
|
|
await page.waitForFunction(() => !document.querySelector('.el-message'))
|
|
await page.screenshot({ path: '/tmp/doclib-upload.png', fullPage: true })
|
|
await upload.getByRole('button', { name: '完成', exact: true }).click()
|
|
await page.screenshot({ path: '/tmp/doclib-desktop.png', fullPage: true })
|
|
await page.getByPlaceholder('搜索文档名称').fill('不存在')
|
|
await page.getByRole('button', { name: '搜索', exact: true }).click()
|
|
await page.getByText('没有匹配的文档').waitFor()
|
|
failList = true
|
|
await page.getByRole('button', { name: '刷新', exact: true }).click()
|
|
await page.getByText('文档加载失败,请点击刷新重试').waitFor()
|
|
failList = false
|
|
await page.getByRole('button', { name: '刷新', exact: true }).click()
|
|
await page.getByText('没有匹配的文档').waitFor()
|
|
await page.getByPlaceholder('搜索文档名称').fill('')
|
|
await page.getByRole('button', { name: '搜索', exact: true }).click()
|
|
await page.locator('.doclib-file-text .el-link').filter({ hasText: '产品资料.pdf' }).waitFor()
|
|
await page.locator('.el-table__body .el-checkbox').first().click()
|
|
await page.getByRole('button', { name: '删除', exact: true }).click()
|
|
await page.getByRole('button', { name: '确认删除', exact: true }).click()
|
|
await page.getByText('这里还没有文档', { exact: true }).waitFor()
|
|
assert.match(await page.locator('.doclib-selected').innerText(), /0/)
|
|
await page.setViewportSize({ width: 700, height: 900 })
|
|
assert.equal(
|
|
await page.locator('.doclib-layout').evaluate((el) => getComputedStyle(el).flexDirection),
|
|
'column'
|
|
)
|
|
assert.equal(deletes, 1)
|
|
assert.deepEqual(errors, [])
|
|
console.log(
|
|
'PASS doclib browser: roots, shared permissions, selection reset, detail, sharing, folders, upload/validation, search, failed load/retry, responsive layout'
|
|
)
|
|
} catch (error) {
|
|
console.log('PAGE', await page.locator('body').innerText(), errors)
|
|
await page.screenshot({ path: '/tmp/doclib-browser-failure.png', fullPage: true })
|
|
throw error
|
|
} finally {
|
|
await browser.close()
|
|
}
|