@@ -5,7 +5,10 @@ const Module = require("node:module");
55const fakeClipboard = {
66 text : "" ,
77 html : "" ,
8+ rtf : "" ,
9+ image : null ,
810 formats : [ "text/plain" ] ,
11+ writes : [ ] ,
912 availableFormats ( ) {
1013 return this . formats ;
1114 } ,
@@ -14,20 +17,46 @@ const fakeClipboard = {
1417 } ,
1518 writeText ( text ) {
1619 this . text = text ;
20+ this . html = "" ;
21+ this . rtf = "" ;
22+ this . image = null ;
23+ this . formats = [ "text/plain" ] ;
24+ this . writes . push ( [ "writeText" , text ] ) ;
1725 } ,
1826 readHTML ( ) {
1927 return this . html ;
2028 } ,
29+ readRTF ( ) {
30+ return this . rtf ;
31+ } ,
2132 write ( payload ) {
22- this . text = payload . text ;
23- this . html = payload . html ;
33+ this . text = payload . text || "" ;
34+ this . html = payload . html || "" ;
35+ this . rtf = payload . rtf || "" ;
36+ this . image = payload . image || null ;
37+ this . formats = [ ] ;
38+ if ( Object . hasOwn ( payload , "text" ) ) this . formats . push ( "text/plain" ) ;
39+ if ( Object . hasOwn ( payload , "html" ) ) this . formats . push ( "text/html" ) ;
40+ if ( Object . hasOwn ( payload , "rtf" ) ) this . formats . push ( "text/rtf" ) ;
41+ if ( Object . hasOwn ( payload , "image" ) ) this . formats . push ( "image/png" ) ;
42+ this . writes . push ( [ "write" , payload ] ) ;
2443 } ,
2544 readImage ( ) {
26- return { isEmpty : ( ) => true } ;
45+ return this . image || emptyImage ;
46+ } ,
47+ writeImage ( image ) {
48+ this . text = "" ;
49+ this . html = "" ;
50+ this . rtf = "" ;
51+ this . image = image ;
52+ this . formats = image && ! image . isEmpty ( ) ? [ "image/png" ] : [ ] ;
53+ this . writes . push ( [ "writeImage" , image ] ) ;
2754 } ,
28- writeImage ( ) { } ,
2955} ;
3056
57+ const emptyImage = { isEmpty : ( ) => true } ;
58+ const nonEmptyImage = { isEmpty : ( ) => false } ;
59+
3160const originalLoad = Module . _load ;
3261Module . _load = function loadWithElectronMock ( request , parent , isMain ) {
3362 if ( request === "electron" ) {
@@ -44,12 +73,48 @@ Module._load = function loadWithElectronMock(request, parent, isMain) {
4473const ClipboardManager = require ( "../../src/helpers/clipboard" ) ;
4574Module . _load = originalLoad ;
4675
47- function resetClipboard ( ) {
48- fakeClipboard . text = "" ;
49- fakeClipboard . html = "" ;
50- fakeClipboard . formats = [ "text/plain" ] ;
76+ function resetClipboard ( {
77+ text = "" ,
78+ html = "" ,
79+ rtf = "" ,
80+ image = null ,
81+ formats = [ "text/plain" ] ,
82+ } = { } ) {
83+ fakeClipboard . text = text ;
84+ fakeClipboard . html = html ;
85+ fakeClipboard . rtf = rtf ;
86+ fakeClipboard . image = image ;
87+ fakeClipboard . formats = formats ;
88+ fakeClipboard . writes = [ ] ;
5189}
5290
91+ test ( "restore preserves rich clipboard formats atomically" , ( ) => {
92+ resetClipboard ( {
93+ formats : [ "text/html" , "text/rtf" , "text/plain" , "image/png" ] ,
94+ text : "plain before" ,
95+ html : "<b>html before</b>" ,
96+ rtf : "{\\rtf1 before}" ,
97+ image : nonEmptyImage ,
98+ } ) ;
99+ const manager = new ClipboardManager ( ) ;
100+
101+ const snapshot = manager . _saveClipboard ( ) ;
102+ fakeClipboard . writeText ( "dictated text" ) ;
103+ manager . _restoreClipboard ( snapshot ) ;
104+
105+ assert . deepEqual ( [ ...fakeClipboard . availableFormats ( ) ] . sort ( ) , [
106+ "image/png" ,
107+ "text/html" ,
108+ "text/plain" ,
109+ "text/rtf" ,
110+ ] ) ;
111+ assert . equal ( fakeClipboard . text , "plain before" ) ;
112+ assert . equal ( fakeClipboard . html , "<b>html before</b>" ) ;
113+ assert . equal ( fakeClipboard . rtf , "{\\rtf1 before}" ) ;
114+ assert . equal ( fakeClipboard . image , nonEmptyImage ) ;
115+ assert . equal ( fakeClipboard . writes . at ( - 1 ) [ 0 ] , "write" ) ;
116+ } ) ;
117+
53118test ( "restore runs when clipboard still contains the pasted text" , async ( ) => {
54119 resetClipboard ( ) ;
55120 fakeClipboard . text = "dictated text" ;
0 commit comments