优化构架
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { copyText } from './copyText'
|
||||
|
||||
describe('copyText', () => {
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks()
|
||||
vi.unstubAllGlobals()
|
||||
Reflect.deleteProperty(document, 'execCommand')
|
||||
document.querySelectorAll('textarea[aria-hidden="true"]').forEach((element) => element.remove())
|
||||
})
|
||||
|
||||
it('uses the Clipboard API when it is available', async () => {
|
||||
const writeText = vi.fn().mockResolvedValue(undefined)
|
||||
vi.stubGlobal('navigator', { clipboard: { writeText } })
|
||||
|
||||
await copyText('request-123')
|
||||
|
||||
expect(writeText).toHaveBeenCalledWith('request-123')
|
||||
})
|
||||
|
||||
it('falls back to a temporary textarea when Clipboard API access is denied', async () => {
|
||||
vi.stubGlobal('navigator', { clipboard: { writeText: vi.fn().mockRejectedValue(new Error('denied')) } })
|
||||
const execCommand = vi.fn().mockReturnValue(true)
|
||||
Object.defineProperty(document, 'execCommand', { configurable: true, value: execCommand })
|
||||
|
||||
await copyText('trace-456')
|
||||
|
||||
expect(execCommand).toHaveBeenCalledWith('copy')
|
||||
expect(document.querySelector('textarea[aria-hidden="true"]')).toBeNull()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,35 @@
|
||||
export async function copyText(value: string) {
|
||||
if (typeof navigator !== 'undefined' && navigator.clipboard?.writeText) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(value)
|
||||
return
|
||||
} catch {
|
||||
// In insecure development contexts the Clipboard API may exist but reject.
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof document === 'undefined' || !document.body) {
|
||||
throw new Error('Clipboard is unavailable')
|
||||
}
|
||||
|
||||
const textarea = document.createElement('textarea')
|
||||
textarea.value = value
|
||||
textarea.readOnly = true
|
||||
textarea.setAttribute('aria-hidden', 'true')
|
||||
Object.assign(textarea.style, {
|
||||
position: 'fixed',
|
||||
inset: '0 auto auto -9999px',
|
||||
opacity: '0',
|
||||
pointerEvents: 'none',
|
||||
})
|
||||
document.body.appendChild(textarea)
|
||||
textarea.select()
|
||||
|
||||
try {
|
||||
if (typeof document.execCommand !== 'function' || !document.execCommand('copy')) {
|
||||
throw new Error('Clipboard copy failed')
|
||||
}
|
||||
} finally {
|
||||
textarea.remove()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user