@@ -35,6 +35,30 @@ const hyperframesHtml = `<!doctype html>
3535 </body>
3636</html>` ;
3737
38+ const runtimeDeckHtml = `<!doctype html>
39+ <html>
40+ <head>
41+ <title>Runtime Deck</title>
42+ <script>
43+ const style = document.createElement("style");
44+ style.textContent = ".runtime { color: rgb(1, 2, 3); }";
45+ document.head.appendChild(style);
46+ </script>
47+ </head>
48+ <body>
49+ <section class="slide runtime" data-slide-id="1"><h1>Runtime slide one</h1></section>
50+ <section class="slide runtime" data-slide-id="2"><h1>Runtime slide two</h1></section>
51+ </body>
52+ </html>` ;
53+
54+ const runtimePlainHtml = `<!doctype html>
55+ <html><head><script>
56+ const style = document.createElement("style");
57+ style.textContent = ".runtime { color: rgb(1, 2, 3); }";
58+ document.head.appendChild(style);
59+ </script></head>
60+ <body><p class="runtime">Runtime source-tab content</p></body></html>` ;
61+
3862async function seedStore ( page : Page , opts : SeedOptions ) {
3963 const now = 1_700_000_000_000 ;
4064 const task = {
@@ -78,6 +102,30 @@ async function seedStore(page: Page, opts: SeedOptions) {
78102 ) ;
79103}
80104
105+ async function captureClipboardHtml ( page : Page ) {
106+ await page . evaluate ( ( ) => {
107+ Object . defineProperty ( window , "ClipboardItem" , {
108+ configurable : true ,
109+ value : class ClipboardItem {
110+ readonly items : Record < string , Blob > ;
111+ constructor ( items : Record < string , Blob > ) {
112+ this . items = items ;
113+ }
114+ } ,
115+ } ) ;
116+ Object . defineProperty ( navigator , "clipboard" , {
117+ configurable : true ,
118+ value : {
119+ write : async ( items : Array < { items : Record < string , Blob > } > ) => {
120+ const blob = items [ 0 ] ?. items [ "text/html" ] ;
121+ ( window as typeof window & { __wechatClipboardHtml ?: string } ) . __wechatClipboardHtml =
122+ blob ? await blob . text ( ) : "" ;
123+ } ,
124+ } ,
125+ } ) ;
126+ } ) ;
127+ }
128+
81129test . describe ( "Export menu" , ( ) => {
82130 test ( "keeps Remotion hidden for regular HTML exports" , async ( { page } ) => {
83131 await seedStore ( page , { html : plainHtml } ) ;
@@ -96,6 +144,48 @@ test.describe("Export menu", () => {
96144 await expect ( menu . getByRole ( "button" , { name : / R e m o t i o n p r o j e c t / } ) ) . toHaveCount ( 0 ) ;
97145 } ) ;
98146
147+ test ( "keeps computed styles when exporting from Source and Log tabs" , async ( { page } ) => {
148+ await seedStore ( page , { html : runtimePlainHtml } ) ;
149+ await page . goto ( "/" ) ;
150+ await captureClipboardHtml ( page ) ;
151+
152+ for ( const tab of [ / S o u r c e / , / L o g / ] ) {
153+ await page . getByRole ( "button" , { name : tab } ) . click ( ) ;
154+ await page . evaluate ( ( ) => {
155+ ( window as typeof window & { __wechatClipboardHtml ?: string } ) . __wechatClipboardHtml = "" ;
156+ } ) ;
157+ await page . getByRole ( "button" , { name : / e x p o r t / i } ) . click ( ) ;
158+ await page . getByTestId ( "export-menu" ) . getByRole ( "button" , { name : / W e C h a t / } ) . click ( ) ;
159+
160+ await expect . poll ( ( ) =>
161+ page . evaluate ( ( ) => ( window as typeof window & { __wechatClipboardHtml ?: string } ) . __wechatClipboardHtml ?? "" ) ,
162+ ) . toContain ( "Runtime source-tab content" ) ;
163+ const copied = await page . evaluate ( ( ) =>
164+ ( window as typeof window & { __wechatClipboardHtml ?: string } ) . __wechatClipboardHtml ?? "" ,
165+ ) ;
166+ expect ( copied ) . toContain ( "color: rgb(1, 2, 3)" ) ;
167+ }
168+ } ) ;
169+
170+ test ( "exports every computed-styled slide when slide 2 is selected" , async ( { page } ) => {
171+ await seedStore ( page , { html : runtimeDeckHtml } ) ;
172+ await page . goto ( "/" ) ;
173+ await captureClipboardHtml ( page ) ;
174+
175+ await page . getByRole ( "button" , { name : "2" , exact : true } ) . click ( ) ;
176+ await page . getByRole ( "button" , { name : / e x p o r t / i } ) . click ( ) ;
177+ await page . getByTestId ( "export-menu" ) . getByRole ( "button" , { name : / W e C h a t / } ) . click ( ) ;
178+
179+ await expect . poll ( ( ) =>
180+ page . evaluate ( ( ) => ( window as typeof window & { __wechatClipboardHtml ?: string } ) . __wechatClipboardHtml ?? "" ) ,
181+ ) . toContain ( "Runtime slide one" ) ;
182+ const copied = await page . evaluate ( ( ) =>
183+ ( window as typeof window & { __wechatClipboardHtml ?: string } ) . __wechatClipboardHtml ?? "" ,
184+ ) ;
185+ expect ( copied ) . toContain ( "Runtime slide two" ) ;
186+ expect ( copied ) . toContain ( "color: rgb(1, 2, 3)" ) ;
187+ } ) ;
188+
99189 test ( "exports a Hyperframes Remotion project zip from the UI" , async ( { page } ) => {
100190 await seedStore ( page , { html : hyperframesHtml } ) ;
101191
0 commit comments