用户要求去掉多余菜单。右键命中图片时只出:超链接…/调整图片 大小…/上传到 S3(未上传图才有)/剪切/复制/粘贴;加粗、斜体、 删除线、行内代码等文本格式项与全选、源码模式对图片没意义, 不再出现(文本右键菜单不变)。配套:右键图片先把它设为节点 选区,描边/手柄随之出现,剪切/复制/Delete 都作用在这张图上。 vitest 153+2、构建通过。
78 lines
3.5 KiB
TypeScript
78 lines
3.5 KiB
TypeScript
// 编辑区右键菜单:条目随模式/选区变化,点击回传动作并关闭。
|
||
import { describe, it, expect, vi } from 'vitest'
|
||
import { createRoot } from 'react-dom/client'
|
||
import { act } from 'react-dom/test-utils'
|
||
import EditorContextMenu from '../src/components/EditorContextMenu'
|
||
|
||
async function renderMenu(props: Record<string, unknown> = {}) {
|
||
const container = document.createElement('div')
|
||
document.body.appendChild(container)
|
||
const root = createRoot(container)
|
||
const actions: string[] = []
|
||
let closed = 0
|
||
await act(async () => {
|
||
root.render(
|
||
<EditorContextMenu
|
||
x={10} y={10} hasSelection={false} imageSrc={null} sourceMode={false}
|
||
onAction={(a) => actions.push(a)}
|
||
onClose={() => { closed += 1 }}
|
||
{...props}
|
||
/>,
|
||
)
|
||
})
|
||
return { container, root, actions, closedCount: () => closed }
|
||
}
|
||
|
||
const btn = (c: HTMLElement, text: string) => [...c.querySelectorAll('button')].find((b) => b.textContent === text)
|
||
|
||
describe('编辑区右键菜单', () => {
|
||
it('无选区时剪切/复制禁用,点加粗回传 bold 并关闭', async () => {
|
||
const { container, root, actions, closedCount } = await renderMenu()
|
||
expect(btn(container, '剪切')?.disabled).toBe(true)
|
||
expect(btn(container, '复制')?.disabled).toBe(true)
|
||
expect(btn(container, '粘贴')?.disabled).toBe(false)
|
||
await act(async () => { btn(container, '加粗')?.dispatchEvent(new MouseEvent('click', { bubbles: true })) })
|
||
expect(actions).toEqual(['bold'])
|
||
expect(closedCount()).toBe(1)
|
||
await act(async () => { root.unmount() })
|
||
container.remove()
|
||
})
|
||
|
||
it('命中本地图片时多一项「上传到 S3」;网络图片不出现', async () => {
|
||
const local = await renderMenu({ imageSrc: 'doc.assets/a.png' })
|
||
const up = btn(local.container, '上传到 S3')
|
||
expect(up).toBeTruthy()
|
||
await act(async () => { up?.dispatchEvent(new MouseEvent('click', { bubbles: true })) })
|
||
expect(local.actions).toEqual(['uploadS3'])
|
||
await act(async () => { local.root.unmount() })
|
||
local.container.remove()
|
||
const remote = await renderMenu({ imageSrc: 'https://cdn.example.com/a.png' })
|
||
expect(btn(remote.container, '上传到 S3')).toBeUndefined()
|
||
await act(async () => { remote.root.unmount() })
|
||
remote.container.remove()
|
||
})
|
||
|
||
it('命中图片时是精简专用菜单:无格式项/全选/源码模式,有超链接与调整大小', async () => {
|
||
const { container, root, actions } = await renderMenu({ imageSrc: 'https://cdn.example.com/a.png', hasSelection: true })
|
||
for (const t of ['加粗', '斜体', '删除线', '行内代码', '全选', '源码模式', '上传到 S3']) {
|
||
expect(btn(container, t)).toBeUndefined()
|
||
}
|
||
for (const t of ['超链接…', '调整图片大小…', '剪切', '复制', '粘贴']) {
|
||
expect(btn(container, t)).toBeTruthy()
|
||
}
|
||
await act(async () => { btn(container, '调整图片大小…')?.dispatchEvent(new MouseEvent('click', { bubbles: true })) })
|
||
expect(actions).toEqual(['imageSize'])
|
||
await act(async () => { root.unmount() })
|
||
container.remove()
|
||
})
|
||
|
||
it('源码模式只出编辑命令与「即时渲染」', async () => {
|
||
const { container, root } = await renderMenu({ sourceMode: true, hasSelection: true })
|
||
expect(btn(container, '加粗')).toBeUndefined()
|
||
expect(btn(container, '即时渲染')).toBeTruthy()
|
||
expect(btn(container, '剪切')?.disabled).toBe(false)
|
||
await act(async () => { root.unmount() })
|
||
container.remove()
|
||
})
|
||
})
|