Rust 新增 s3.rs:SigV4 签名 + PUT Object(reqwest blocking+rustls, 签名对照 AWS 官方示例向量逐字一致;同份代码对本地模拟 S3 端到端 实测通过)。命令 s3_upload_image / s3_test_connection(总数 30 对账)。 配置存 UiState.s3(本机偏好),设置弹窗含测试连接与自动上传开关。 未上传判定 = src 非 http/data/blob 的本地引用;上传成功后同 src 的 图片节点一次事务回换为 S3 地址,本地 .assets 文件保留。 入口:粘贴/插入后自动上传回换(扑空重试一次、失败必提示);右键 命中本地图片多一项「上传到 S3」;文件菜单 + 状态栏批量上传带进度 弹窗。验证:vitest 133+2、tsc、构建通过,设置弹窗截图核对。
54 lines
1.9 KiB
TypeScript
54 lines
1.9 KiB
TypeScript
// 编辑器图片节点操作(docs/30):收集 src、按旧 src 回换、按 DOM 元素反查 src。
|
||
import { describe, it, expect } from 'vitest'
|
||
import { createMarkdownEditor, getMarkdown, collectImageSrcs, replaceImageSrc, imageSrcAtElement } from '../src/editor/editor'
|
||
|
||
const DOC = [
|
||
'# 图',
|
||
'',
|
||
'',
|
||
'',
|
||
'',
|
||
'',
|
||
'',
|
||
'',
|
||
].join('\n')
|
||
|
||
async function makeEditor() {
|
||
const root = document.createElement('div')
|
||
document.body.appendChild(root)
|
||
const editor = createMarkdownEditor(root, DOC)
|
||
await editor.create()
|
||
return { root, editor }
|
||
}
|
||
|
||
describe('editor image ops', () => {
|
||
it('收集全部图片 src 并去重', async () => {
|
||
const { root, editor } = await makeEditor()
|
||
expect(collectImageSrcs(editor)).toEqual(['doc.assets/a.png', 'https://cdn.example.com/b.png'])
|
||
await editor.destroy()
|
||
root.remove()
|
||
})
|
||
|
||
it('按旧 src 回换全部同名图片节点(含重复引用)', async () => {
|
||
const { root, editor } = await makeEditor()
|
||
const n = replaceImageSrc(editor, 'doc.assets/a.png', 'https://s3.example.com/a.png')
|
||
expect(n).toBe(2)
|
||
const md = getMarkdown(editor)
|
||
expect(md).toContain('https://s3.example.com/a.png')
|
||
expect(md).not.toContain('doc.assets/a.png')
|
||
expect(collectImageSrcs(editor)).toEqual(['https://s3.example.com/a.png', 'https://cdn.example.com/b.png'])
|
||
await editor.destroy()
|
||
root.remove()
|
||
})
|
||
|
||
it('按 <img> 元素反查节点 src;非图片元素返回 null', async () => {
|
||
const { root, editor } = await makeEditor()
|
||
const img = root.querySelector('img')
|
||
expect(img).not.toBeNull()
|
||
expect(imageSrcAtElement(editor, img as HTMLElement)).toBe('doc.assets/a.png')
|
||
expect(imageSrcAtElement(editor, root)).toBeNull()
|
||
await editor.destroy()
|
||
root.remove()
|
||
})
|
||
})
|