mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-08 06:30:04 +00:00
Backport of #7103 to `core/1.33` Automatically created by backport workflow. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-7246-backport-core-1-33-fix-handle-Unicode-characters-in-clipboard-copy-paste-and-add-Paste-2c36d73d365081d79d8de04456bdf9d8) by [Unito](https://www.unito.io) Co-authored-by: Terry Jia <terryjia88@gmail.com> Co-authored-by: github-actions <github-actions@github.com>
106 lines
3.5 KiB
TypeScript
106 lines
3.5 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
|
|
/**
|
|
* Encodes a UTF-8 string to base64 (same logic as useCopy.ts)
|
|
*/
|
|
function encodeClipboardData(data: string): string {
|
|
return btoa(
|
|
String.fromCharCode(...Array.from(new TextEncoder().encode(data)))
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Decodes base64 to UTF-8 string (same logic as usePaste.ts)
|
|
*/
|
|
function decodeClipboardData(base64: string): string {
|
|
const binaryString = atob(base64)
|
|
const bytes = Uint8Array.from(binaryString, (c) => c.charCodeAt(0))
|
|
return new TextDecoder().decode(bytes)
|
|
}
|
|
|
|
describe('Clipboard UTF-8 base64 encoding/decoding', () => {
|
|
it('should handle ASCII-only strings', () => {
|
|
const original = '{"nodes":[{"id":1,"type":"LoadImage"}]}'
|
|
const encoded = encodeClipboardData(original)
|
|
const decoded = decodeClipboardData(encoded)
|
|
expect(decoded).toBe(original)
|
|
})
|
|
|
|
it('should handle Chinese characters in localized_name', () => {
|
|
const original =
|
|
'{"nodes":[{"id":1,"type":"LoadImage","localized_name":"图像"}]}'
|
|
const encoded = encodeClipboardData(original)
|
|
const decoded = decodeClipboardData(encoded)
|
|
expect(decoded).toBe(original)
|
|
})
|
|
|
|
it('should handle Japanese characters', () => {
|
|
const original = '{"localized_name":"画像を読み込む"}'
|
|
const encoded = encodeClipboardData(original)
|
|
const decoded = decodeClipboardData(encoded)
|
|
expect(decoded).toBe(original)
|
|
})
|
|
|
|
it('should handle Korean characters', () => {
|
|
const original = '{"localized_name":"이미지 불러오기"}'
|
|
const encoded = encodeClipboardData(original)
|
|
const decoded = decodeClipboardData(encoded)
|
|
expect(decoded).toBe(original)
|
|
})
|
|
|
|
it('should handle mixed ASCII and Unicode characters', () => {
|
|
const original =
|
|
'{"nodes":[{"id":1,"type":"LoadImage","localized_name":"加载图像","label":"Load Image 图片"}]}'
|
|
const encoded = encodeClipboardData(original)
|
|
const decoded = decodeClipboardData(encoded)
|
|
expect(decoded).toBe(original)
|
|
})
|
|
|
|
it('should handle emoji characters', () => {
|
|
const original = '{"title":"Test Node 🎨🖼️"}'
|
|
const encoded = encodeClipboardData(original)
|
|
const decoded = decodeClipboardData(encoded)
|
|
expect(decoded).toBe(original)
|
|
})
|
|
|
|
it('should handle empty string', () => {
|
|
const original = ''
|
|
const encoded = encodeClipboardData(original)
|
|
const decoded = decodeClipboardData(encoded)
|
|
expect(decoded).toBe(original)
|
|
})
|
|
|
|
it('should handle complex node data with multiple Unicode fields', () => {
|
|
const original = JSON.stringify({
|
|
nodes: [
|
|
{
|
|
id: 1,
|
|
type: 'LoadImage',
|
|
localized_name: '图像',
|
|
inputs: [{ localized_name: '图片', name: 'image' }],
|
|
outputs: [{ localized_name: '输出', name: 'output' }]
|
|
}
|
|
],
|
|
groups: [{ title: '预处理组 🔧' }],
|
|
links: []
|
|
})
|
|
const encoded = encodeClipboardData(original)
|
|
const decoded = decodeClipboardData(encoded)
|
|
expect(decoded).toBe(original)
|
|
expect(JSON.parse(decoded)).toEqual(JSON.parse(original))
|
|
})
|
|
|
|
it('should produce valid base64 output', () => {
|
|
const original = '{"localized_name":"中文测试"}'
|
|
const encoded = encodeClipboardData(original)
|
|
// Base64 should only contain valid characters
|
|
expect(encoded).toMatch(/^[A-Za-z0-9+/=]+$/)
|
|
})
|
|
|
|
it('should fail with plain btoa for non-Latin1 characters', () => {
|
|
const original = '{"localized_name":"图像"}'
|
|
// This demonstrates why we need TextEncoder - plain btoa fails
|
|
expect(() => btoa(original)).toThrow()
|
|
})
|
|
})
|