-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCommon.test.tsx
More file actions
134 lines (116 loc) · 5.13 KB
/
Common.test.tsx
File metadata and controls
134 lines (116 loc) · 5.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/* Common.test.tsx — unit tests for shared component helpers.
*
* Currently focused on the clipboard helper (§10.10). The helper has two
* paths: the modern async Clipboard API and the legacy execCommand
* fallback for HTTP origins / older Safari. We verify both paths and the
* total-failure case so the v1 console.warn surface in callers is the
* only thing surfacing the miss.
*/
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import { copyToClipboard, displayName, isUnnamed } from './Common'
describe('displayName / isUnnamed — mandatory-name fallback', () => {
it('returns the name verbatim when present', () => {
expect(displayName('my-app-db', 'postgres')).toBe('my-app-db')
expect(isUnnamed('my-app-db')).toBe(false)
})
it('falls back to "(unnamed <type>)" for null / empty / whitespace names', () => {
expect(displayName(null, 'postgres')).toBe('(unnamed postgres)')
expect(displayName(undefined, 'redis')).toBe('(unnamed redis)')
expect(displayName('', 'deploy')).toBe('(unnamed deploy)')
expect(displayName(' ', 'mongodb')).toBe('(unnamed mongodb)')
})
it('falls back to bare "(unnamed)" when no type is supplied', () => {
expect(displayName(null)).toBe('(unnamed)')
expect(displayName('')).toBe('(unnamed)')
})
it('isUnnamed reports true only for blank names', () => {
expect(isUnnamed(null)).toBe(true)
expect(isUnnamed(undefined)).toBe(true)
expect(isUnnamed('')).toBe(true)
expect(isUnnamed(' ')).toBe(true)
expect(isUnnamed('x')).toBe(false)
})
it('trims surrounding whitespace from real names', () => {
expect(displayName(' spaced ', 'postgres')).toBe('spaced')
})
})
describe('copyToClipboard', () => {
let originalClipboardDescriptor: PropertyDescriptor | undefined
let originalExecCommand: typeof document.execCommand
beforeEach(() => {
originalClipboardDescriptor = Object.getOwnPropertyDescriptor(navigator, 'clipboard')
originalExecCommand = document.execCommand
})
afterEach(() => {
// Restore the original clipboard descriptor (or remove if there
// wasn't one). jsdom's default is no clipboard, so just leaving the
// mock would leak into other test files.
if (originalClipboardDescriptor) {
Object.defineProperty(navigator, 'clipboard', originalClipboardDescriptor)
} else {
try { delete (navigator as any).clipboard } catch { /* ignore */ }
}
document.execCommand = originalExecCommand
})
it('uses navigator.clipboard.writeText on the happy path', async () => {
const writeText = vi.fn().mockResolvedValue(undefined)
Object.defineProperty(navigator, 'clipboard', {
value: { writeText },
configurable: true,
})
const ok = await copyToClipboard('hello')
expect(ok).toBe(true)
expect(writeText).toHaveBeenCalledTimes(1)
expect(writeText).toHaveBeenCalledWith('hello')
})
it('falls back to execCommand when navigator.clipboard.writeText throws', async () => {
const writeText = vi.fn().mockRejectedValue(new Error('NotAllowedError'))
Object.defineProperty(navigator, 'clipboard', {
value: { writeText },
configurable: true,
})
const execCommand = vi.fn().mockReturnValue(true)
document.execCommand = execCommand as unknown as typeof document.execCommand
const ok = await copyToClipboard('fallback-text')
expect(ok).toBe(true)
// Modern path was attempted...
expect(writeText).toHaveBeenCalledTimes(1)
// ...and the legacy path ran after it threw.
expect(execCommand).toHaveBeenCalledWith('copy')
// The transient textarea must be cleaned up so we don't leak DOM.
expect(document.querySelectorAll('textarea').length).toBe(0)
})
it('uses the execCommand fallback when navigator.clipboard is missing entirely', async () => {
// Simulate HTTP origin / locked-down browser: no clipboard at all.
Object.defineProperty(navigator, 'clipboard', {
value: undefined,
configurable: true,
})
const execCommand = vi.fn().mockReturnValue(true)
document.execCommand = execCommand as unknown as typeof document.execCommand
const ok = await copyToClipboard('no-clipboard')
expect(ok).toBe(true)
expect(execCommand).toHaveBeenCalledWith('copy')
})
it('returns false when both paths fail', async () => {
const writeText = vi.fn().mockRejectedValue(new Error('blocked'))
Object.defineProperty(navigator, 'clipboard', {
value: { writeText },
configurable: true,
})
document.execCommand = (() => { throw new Error('execCommand denied') }) as unknown as typeof document.execCommand
const ok = await copyToClipboard('nope')
expect(ok).toBe(false)
})
it('returns false (not throws) when execCommand returns false', async () => {
// Some browsers refuse silently — execCommand returns false rather
// than throwing. The helper must propagate that as `false`.
Object.defineProperty(navigator, 'clipboard', {
value: undefined,
configurable: true,
})
document.execCommand = vi.fn().mockReturnValue(false) as unknown as typeof document.execCommand
const ok = await copyToClipboard('refused')
expect(ok).toBe(false)
})
})