@@ -109,14 +109,39 @@ define(function (require, exports, module) {
109109 return str . replace ( allSpacesRE , " " ) ;
110110 }
111111
112- async function getSourceFromBrowser ( liveDoc ) {
113- let doneSyncing = false , browserText ;
114- liveDoc . getSourceFromBrowser ( ) . done ( function ( text ) {
115- browserText = text ;
116- } ) . always ( function ( ) {
117- doneSyncing = true ;
118- } ) ;
119- await awaitsFor ( function ( ) { return doneSyncing ; } , "Browser to sync changes" , 20000 ) ;
112+ /**
113+ * A linked stylesheet gets its live document only once the page reports it back, which can
114+ * trail the page's own load. Wait for it rather than reading it straight away.
115+ * @return {Promise<Object> } the live document
116+ */
117+ async function waitsForLiveDocForPath ( fullPath ) {
118+ await awaitsFor ( function ( ) {
119+ return ! ! LiveDevMultiBrowser . getLiveDocForPath ( fullPath ) ;
120+ } , "live document for " + fullPath , 20000 ) ;
121+ return LiveDevMultiBrowser . getLiveDocForPath ( fullPath ) ;
122+ }
123+
124+ /**
125+ * Read a live document back from the browser until it passes the check: an edit pushed
126+ * a moment ago may still be on its way.
127+ * @return {Promise<string> } the browser's text
128+ */
129+ async function waitsForBrowserSource ( liveDoc , isReady , message ) {
130+ let browserText , reading = false ;
131+ await awaitsFor ( function ( ) {
132+ if ( browserText !== undefined && isReady ( browserText ) ) {
133+ return true ;
134+ }
135+ if ( ! reading ) {
136+ reading = true ;
137+ liveDoc . getSourceFromBrowser ( ) . done ( function ( text ) {
138+ browserText = text ;
139+ } ) . always ( function ( ) {
140+ reading = false ;
141+ } ) ;
142+ }
143+ return false ;
144+ } , message , 20000 ) ;
120145 return browserText ;
121146 }
122147
@@ -196,6 +221,17 @@ define(function (require, exports, module) {
196221 editor && editor . setCursorPos ( { line : 0 , ch : 0 } ) ;
197222 }
198223
224+ /**
225+ * Hiding the panel closes Live Preview when no preview client is connected, and in a
226+ * test window showing the panel again does not reopen it: tests start Live Preview
227+ * themselves. Reopen it the way the app does, so the preview server comes back.
228+ */
229+ function _reopenLiveDevIfStopped ( ) {
230+ if ( LiveDevMultiBrowser . status === LiveDevMultiBrowser . STATUS_INACTIVE ) {
231+ LiveDevMultiBrowser . open ( ) ;
232+ }
233+ }
234+
199235 async function waitsForLiveDevelopmentToOpen ( ) {
200236 LiveDevMultiBrowser . open ( ) ;
201237 try {
@@ -377,8 +413,10 @@ define(function (require, exports, module) {
377413 localText = curDoc . getText ( ) ;
378414 localText += styleTextAdd ;
379415 curDoc . setText ( localText ) ;
380- liveDoc = LiveDevMultiBrowser . getLiveDocForPath ( testFolder + "/simple1.css" ) ;
381- browserText = await getSourceFromBrowser ( liveDoc ) ;
416+ liveDoc = await waitsForLiveDocForPath ( testFolder + "/simple1.css" ) ;
417+ browserText = await waitsForBrowserSource ( liveDoc , function ( text ) {
418+ return text . includes ( "testClass" ) ;
419+ } , "the edited rule to reach the browser" ) ;
382420 browserText = browserText . replace ( / u r l \( ' h t t p : \/ \/ 1 2 7 \. 0 \. 0 \. 1 : \d + \/ i m p o r t 1 \. c s s ' \) ; / , "url('import1.css');" ) ;
383421
384422 expect ( fixSpaces ( browserText ) . includes ( fixSpaces ( styleTextAdd ) ) ) . toBeTrue ( ) ;
@@ -434,8 +472,10 @@ define(function (require, exports, module) {
434472 localText = curDoc . getText ( ) ;
435473 localText += "\n .testClass { background-color:#090; }\n" ;
436474 curDoc . setText ( localText ) ;
437- liveDoc = LiveDevMultiBrowser . getLiveDocForPath ( testFolder + "/sub/test.css" ) ;
438- browserText = await getSourceFromBrowser ( liveDoc ) ;
475+ liveDoc = await waitsForLiveDocForPath ( testFolder + "/sub/test.css" ) ;
476+ browserText = await waitsForBrowserSource ( liveDoc , function ( text ) {
477+ return text . includes ( "testClass" ) ;
478+ } , "the edited rule to reach the browser" ) ;
439479
440480 // Drop the port from 127.0.0.1:port so it's easier to work with
441481 browserText = browserText . replace ( / 1 2 7 \. 0 \. 0 \. 1 : \d + / , "127.0.0.1" ) ;
@@ -705,44 +745,44 @@ define(function (require, exports, module) {
705745 "closing all files before opening simple1.css" ) ;
706746 await awaitsForDone ( SpecRunnerUtils . openProjectFiles ( [ "simple1.css" ] ) ,
707747 "simple1.css" ) ;
708- const doc = DocumentManager . getCurrentDocument ( ) ;
709- const text = doc . getText ( ) ;
710- // The original simple1.css should NOT contain background-color:#090
711- // That gets added by a previous test and must be cleaned up
712- // We verify the file doesn't contain #090 background-color and if it does, change expectations
713- // in linux, or if system slow, it will take some time for file system change event to catch
714- // up and update document. so we need to do this below. This is a bug in tests as why is the test not
715- // resetting file properly constantly?
716- const has90 = text . includes ( "background-color:#090" ) ;
717- const firstColor = has90 ? "#090" : "aliceblue" ;
718- const firstColorRGB = has90 ? "rgb(0, 153, 0)" : "rgb(240, 248, 255)" ;
719-
720748 await _openCodeHints ( { line : 3 , ch : 8 } , [ "antiquewhite" ] ) ;
721749
722750 let editor = EditorManager . getActiveEditor ( ) ;
723751 const initialHistoryLength = editor . getHistory ( ) . done . length ;
724- SpecRunnerUtils . simulateKeyEvent ( KeyEvent . DOM_VK_DOWN , "keydown" , testWindow . document . body ) ;
725- await awaitsFor ( function ( ) {
726- // #090 is the content from simple1.css file
727- // this appears as the 2nd item in the codehint menu, from "suggest previously used color" feature
728- return editor . getSelectedText ( ) === firstColor ;
729- } , `expected live hints to update selection to ${ firstColor } ` ) ;
730- await _waitForLivePreviewElementColor ( "testId" , firstColorRGB ) ;
731- SpecRunnerUtils . simulateKeyEvent ( KeyEvent . DOM_VK_DOWN , "keydown" , testWindow . document . body ) ;
732-
733- const secondColor = has90 ? "aliceblue" : "antiquewhite" ;
734- const secondColorRGB = has90 ? "rgb(240, 248, 255)" : "rgb(250, 235, 215)" ;
735- await awaitsFor ( function ( ) {
736- return editor . getSelectedText ( ) === secondColor ;
737- } , `expected live hints to update selection to ${ secondColor } ` ) ;
752+ // Which colors come first is not fixed: the hints suggest colors used earlier, and an
753+ // earlier test's #090 can be among them. Follow whatever the menu offers instead.
754+ const firstColor = await _previewNextColorHint ( editor , "" ) ;
755+ const secondColor = await _previewNextColorHint ( editor , firstColor ) ;
756+ return { historyLength : initialHistoryLength , lastColor : secondColor } ;
757+ }
738758
739- await _waitForLivePreviewElementColor ( "testId" , secondColorRGB ) ; // antiquewhite
759+ /** The browser's computed form of a CSS color, e.g. "rgb(240, 248, 255)" for aliceblue. */
760+ function _computedColor ( color ) {
761+ const probe = testWindow . document . createElement ( "span" ) ;
762+ probe . style . color = color ;
763+ testWindow . document . body . appendChild ( probe ) ;
764+ const computed = testWindow . getComputedStyle ( probe ) . color ;
765+ probe . remove ( ) ;
766+ return computed ;
767+ }
740768
741- return initialHistoryLength ;
769+ /**
770+ * Move to the next color hint: the editor shows it as the selection, and the page shows it.
771+ * @return {Promise<string> } the color previewed
772+ */
773+ async function _previewNextColorHint ( editor , previousColor ) {
774+ SpecRunnerUtils . simulateKeyEvent ( KeyEvent . DOM_VK_DOWN , "keydown" , testWindow . document . body ) ;
775+ let color ;
776+ await awaitsFor ( function ( ) {
777+ color = editor . getSelectedText ( ) ;
778+ return ! ! color && color !== previousColor ;
779+ } , "live hints to preview the next color" ) ;
780+ await _waitForLivePreviewElementColor ( "testId" , _computedColor ( color ) ) ;
781+ return color ;
742782 }
743783
744784 it ( "should Live preview push css code hints selection changes to browser(linked css)" , async function ( ) {
745- const expectedHistoryLength = await _livePreviewCodeHintsCSS ( ) ;
785+ const expectedHistoryLength = ( await _livePreviewCodeHintsCSS ( ) ) . historyLength ;
746786 let editor = EditorManager . getActiveEditor ( ) ;
747787
748788 // now dismiss with escape
@@ -761,7 +801,7 @@ define(function (require, exports, module) {
761801 } , 30000 ) ;
762802
763803 it ( "should Live preview push css code hints selection changes to browser and commit(linked css)" , async function ( ) {
764- const expectedHistoryLength = await _livePreviewCodeHintsCSS ( ) ;
804+ const { historyLength : expectedHistoryLength , lastColor } = await _livePreviewCodeHintsCSS ( ) ;
765805 let editor = EditorManager . getActiveEditor ( ) ;
766806
767807 // now dismiss with escape
@@ -772,11 +812,8 @@ define(function (require, exports, module) {
772812 await awaitsFor ( function ( ) {
773813 return editor . getSelectedText ( ) === "" ;
774814 } , "to restore the text to old state" ) ;
775- // check if we have the new value
776- if ( ! [ "antiquewhite" , "aliceblue" ] . includes ( editor . getToken ( ) . string ) ) {
777- // so depends on the bug in _livePreviewCodeHintsCSS which color is at present.
778- expect ( "color should have beein either aliceblue or antiquewhite" ) . toBeTrue ( ) ;
779- }
815+ // the color previewed last is the one committed
816+ expect ( editor . getToken ( ) . string ) . toBe ( lastColor ) ;
780817
781818 // the undo history should be just one above
782819 expect ( editor . getHistory ( ) . done . length ) . toBe ( expectedHistoryLength + 3 ) ;
@@ -1298,15 +1335,18 @@ define(function (require, exports, module) {
12981335 } , 30000 ) ;
12991336
13001337 async function forRemoteExec ( script , compareFn ) {
1301- let result ;
1338+ let result , replied = false ;
13021339 await awaitsFor (
13031340 function ( ) {
13041341 LiveDevProtocol . evaluate ( script )
13051342 . done ( ( response ) => {
1306- result = JSON . parse ( response . result || "" ) ;
1343+ // An undefined value comes back with no result at all.
1344+ result = response . result ? JSON . parse ( response . result ) : undefined ;
1345+ replied = true ;
13071346 } ) ;
13081347 if ( compareFn ) {
1309- return compareFn ( result ) ;
1348+ // The reply is async: until the first one arrives there is nothing to compare.
1349+ return replied && compareFn ( result ) ;
13101350 }
13111351 // just exec and return if no compare function is specified
13121352 return true ;
@@ -1388,17 +1428,17 @@ define(function (require, exports, module) {
13881428 it ( "should live highlight resize as window size changes" , async function ( ) {
13891429 await awaitsForDone ( SpecRunnerUtils . openProjectFiles ( [ "simple1.html" ] ) ,
13901430 "SpecRunnerUtils.openProjectFiles simple1.html" ) ;
1391- let iFrame = testWindow . document . getElementById ( "panel-live-preview-frame" ) ;
13921431
13931432 await waitsForLiveDevelopmentToOpen ( ) ;
1433+ // Looked up after the preview opened: each page load gets a fresh iframe.
1434+ let iFrame = testWindow . document . getElementById ( "panel-live-preview-frame" ) ;
13941435 let editor = EditorManager . getActiveEditor ( ) ;
13951436 await forRemoteExec ( `_LD.getHighlightCount()` , ( result ) => {
13961437 return result === 0 ;
13971438 } ) ;
13981439
13991440 editor . setCursorPos ( { line : 11 , ch : 10 } ) ;
14001441
1401- await awaits ( 500 ) ;
14021442 await forRemoteExec ( `_LD.getHighlightCount()` , ( result ) => {
14031443 return result === 1 ;
14041444 } ) ;
@@ -1409,12 +1449,10 @@ define(function (require, exports, module) {
14091449 } ) ;
14101450
14111451 iFrame . style . width = "100px" ;
1412- await awaits ( 500 ) ;
14131452 await forRemoteExec ( `_LD.getHighlightStyle(0, 'width')` , ( result ) => {
14141453 return originalWidth !== result ;
14151454 } ) ;
14161455 iFrame . style . width = "100%" ;
1417- await awaits ( 500 ) ;
14181456 await forRemoteExec ( `_LD.getHighlightStyle(0, 'width')` , ( result ) => {
14191457 return originalWidth === result ;
14201458 } ) ;
@@ -1834,34 +1872,31 @@ define(function (require, exports, module) {
18341872 "SpecRunnerUtils.openProjectFiles simple1.html" ) ;
18351873
18361874 await waitsForLiveDevelopmentToOpen ( ) ;
1837- let iFrame = testWindow . document . getElementById ( "panel-live-preview-frame" ) ;
1838- expect ( iFrame . src . endsWith ( `simple1.html` ) )
1839- . toBeTrue ( ) ;
1875+ await _waitForIframeSrc ( "simple1.html" ) ;
18401876
18411877 let pinURLBtn = testWindow . $ ( testWindow . document . getElementById ( "pinURLButton" ) ) ;
18421878 pinURLBtn . click ( ) ;
18431879
18441880 await awaitsForDone ( SpecRunnerUtils . openProjectFiles ( [ "simple2.html" ] ) ,
18451881 "simple2.html" ) ;
1846- await awaits ( 500 ) ;
1847- expect ( iFrame . src . endsWith ( `simple1.html` ) )
1848- . toBeTrue ( ) ;
1882+ // Pinned: the preview stays on simple1.
1883+ await _waitForIframeSrc ( "simple1.html" ) ;
18491884
1850- // now close the live preview panel by clicking on live preview extension icon
1885+ // now hide and show the live preview panel by clicking on live preview extension icon
18511886 let livePreviewBtn = testWindow . $ ( testWindow . document . getElementById ( "toolbar-go-live" ) ) ;
18521887 livePreviewBtn . click ( ) ;
1853- await awaits ( 500 ) ;
1888+ await awaitsFor ( ( ) => ! WorkspaceManager . isPanelVisible ( "live-preview-panel" ) ,
1889+ "live preview panel to hide" ) ;
18541890 livePreviewBtn . click ( ) ;
1855- await awaits ( 500 ) ;
1856- expect ( iFrame . src . endsWith ( `simple1.html` ) )
1857- . toBeTrue ( ) ;
1891+ await awaitsFor ( ( ) => WorkspaceManager . isPanelVisible ( "live-preview-panel" ) ,
1892+ "live preview panel to show" ) ;
1893+ _reopenLiveDevIfStopped ( ) ;
1894+ // Still pinned: the panel shows simple1 again.
1895+ await _waitForIframeSrc ( "simple1.html" ) ;
18581896
1897+ // Unpinned: the preview follows the current file, simple2.
18591898 pinURLBtn . click ( ) ;
1860-
1861- await awaits ( 1000 ) ;
1862- let outerIFrame = testWindow . document . getElementById ( "panel-live-preview-frame" ) ;
1863- let srcURL = new URL ( outerIFrame . src ) ;
1864- expect ( srcURL . pathname . endsWith ( "simple2.html" ) ) . toBeTrue ( ) ;
1899+ await _waitForIframeSrc ( "simple2.html" ) ;
18651900
18661901 await endPreviewSession ( ) ;
18671902 } , 30000 ) ;
0 commit comments