feat: complete WorkBuddy parity and Windows release workflow

This commit is contained in:
xiaohan.yuan committed 2026-10-18 12:45:21 +08:00
1 parent 143516b3a8
commit d5512df549
434 files changed
+54977 -1854

No files matched your search

+40 -4
View File
@@ -112,6 +112,16 @@ if (!process.versions.electron) {
await pause(200)
check('overlay click closes the menu', await read('!!document.querySelector(".conversation-context-menu")'), false)
await step('context-menu-same-as-more')
const contextClicked = await read(`(()=>{const rows=[...document.querySelectorAll('[data-session-id]')];const row=rows[1];if(!row)return null;const ids=rows.map(item=>item.dataset.sessionId);const selected=document.querySelector('[data-selected="true"]')?.dataset.sessionId;row.dispatchEvent(new MouseEvent('contextmenu',{bubbles:true,cancelable:true,button:2,clientX:220,clientY:420}));return {ids,selected}})()`)
const contextMenu = await wait(menuSource, 'task context menu from row right-click')
check('right-click opens the same implemented menu', contextMenu.items.map(item => item.label), snapshots.menu.items.map(item => item.label))
check('right-click opens the menu for the row under the pointer', await read(`document.querySelector('[data-session-id].sidebar__item--menu-open')?.dataset.sessionId`), contextClicked.ids[1])
check('right-click does not switch the active conversation', await read(`document.querySelector('[data-selected="true"]')?.dataset.sessionId`), contextClicked.selected)
check('right-click anchors the menu at the pointer', [Math.round(contextMenu.rect[0]), Math.round(contextMenu.rect[1])], [220, 420])
await read(`document.querySelector('.conversation-context-menu-overlay').click()`)
await wait(`!document.querySelector('.conversation-context-menu')`, 'right-click menu closes')
await step('pin-and-unpin')
await read(openMenu); await wait(menuSource, 'menu for pin')
await read(clickItemByLabel('置顶')); await pause(400)
@@ -151,18 +161,44 @@ if (!process.versions.electron) {
for (const window of windows) if (window !== main) window.destroy()
await pause(200)
await step('archive')
await step('archive-confirm')
await read(openMenu); await wait(menuSource, 'menu for archive')
await read(clickItemByLabel('归档')); await pause(500)
await read(clickItemByLabel('归档'))
await wait(`!!document.querySelector('.task-confirm-dialog[data-task-confirm-kind="archive"]')`, 'archive confirmation')
const archiveConfirm = await read(`(()=>{const dialog=document.querySelector('.task-confirm-dialog');const box=node=>{const r=node.getBoundingClientRect();return [r.x,r.y,r.width,r.height]};const style=getComputedStyle(dialog);return {box:box(dialog),title:dialog.querySelector('.wb-modal__title')?.textContent,desc:dialog.querySelector('.task-confirm-dialog__description')?.textContent,cancel:dialog.querySelector('.task-confirm-dialog__cancel')?.textContent,confirm:dialog.querySelector('.task-confirm-dialog__confirm')?.textContent,padding:style.padding,borderRadius:style.borderRadius}})()`)
check('archive opens a confirmation before changing the task', archiveConfirm.title, '归档任务')
check('archive confirmation points to the in-product archive entry', archiveConfirm.desc, '确认将该任务归档吗?归档后可在侧栏「已归档」中查看并恢复。')
check('archive confirmation does not reintroduce removed data management', archiveConfirm.desc.includes('数据管理'), false)
check('archive confirmation actions use the recovered labels', [archiveConfirm.cancel, archiveConfirm.confirm], ['取消', '确认归档'])
check('archive confirmation uses the recovered 480px shell', [Math.round(archiveConfirm.box[2]), archiveConfirm.padding, archiveConfirm.borderRadius], [480, '24px', '24px'])
await shot('archive-confirm')
await read(`document.querySelector('.task-confirm-dialog__cancel').click()`)
await wait(`!document.querySelector('.task-confirm-dialog')`, 'archive cancellation closes')
check('cancelling archive keeps the task visible', await read(`document.querySelectorAll('[data-session-id]').length`), 2)
await read(openMenu); await wait(menuSource, 'menu for archive confirm')
await read(clickItemByLabel('归档'))
await wait(`!!document.querySelector('.task-confirm-dialog__confirm')`, 'archive confirmation confirm')
await read(`document.querySelector('.task-confirm-dialog__confirm').click()`)
await wait(`document.querySelectorAll('[data-session-id]').length===1`, 'archive completes after confirmation')
const visibleAfterArchive = await read(`document.querySelectorAll('[data-session-id]').length`)
check('archive hides exactly one row', visibleAfterArchive, 1)
check('archive keeps both sessions in the archived listing', await read(`window.ycode.session.listArchived().then(list=>list.length)`), 2)
check('archived session keeps its archivedAt marker', await read(`window.ycode.session.listArchived().then(list=>list.filter(item=>item.archivedAt!==undefined).length)`), 1)
await step('delete')
await step('delete-confirm')
const remainingId = await read(`window.ycode.session.list().then(list=>list[0].id)`)
await read(openMenu); await wait(menuSource, 'menu for delete')
await read(clickItemByLabel('删除任务')); await pause(500)
await read(clickItemByLabel('删除任务'))
await wait(`!!document.querySelector('.task-confirm-dialog[data-task-confirm-kind="delete"]')`, 'delete confirmation')
const deleteConfirm = await read(`(()=>{const dialog=document.querySelector('.task-confirm-dialog');return {title:dialog.querySelector('.wb-modal__title')?.textContent,desc:dialog.querySelector('.task-confirm-dialog__description')?.textContent,cancel:dialog.querySelector('.task-confirm-dialog__cancel')?.textContent,confirm:dialog.querySelector('.task-confirm-dialog__confirm')?.textContent,running:dialog.getAttribute('data-task-confirm-running')}})()`)
check('delete uses the idle confirmation title', deleteConfirm.title, '删除任务?')
check('delete uses the idle confirmation description', deleteConfirm.desc, '删除后,这些任务将从你的所有设备中移除,且无法恢复。')
check('delete confirmation actions use the recovered idle labels', [deleteConfirm.cancel, deleteConfirm.confirm], ['取消', '确认'])
check('idle delete is not marked as running', deleteConfirm.running, null)
await shot('delete-confirm')
await read(`document.querySelector('.task-confirm-dialog__confirm').click()`)
await wait(`window.ycode.session.listArchived().then(list=>!list.some(item=>item.id===${JSON.stringify(remainingId)}))`, 'delete completes after confirmation')
check('delete removes that session from the store', await read(`window.ycode.session.listArchived().then(list=>list.some(item=>item.id===${JSON.stringify(remainingId)}))`), false)
check('delete leaves only the archived session', await read(`window.ycode.session.listArchived().then(list=>list.length)`), 1)
check('no renderer error logs', rendererErrors, [])