@@ -32,6 +32,7 @@ const mockActivity = {
3232 _loadStart : jest . fn ( ) ,
3333 doLoadAnimation : jest . fn ( ) ,
3434 textMsg : jest . fn ( ) ,
35+ errorMsg : jest . fn ( ) ,
3536 stage : { enableDOMEvents : jest . fn ( ) , update : jest . fn ( ) } ,
3637 blocks : { loadNewBlocks : jest . fn ( ) , palettes : { _hideMenus : jest . fn ( ) } , trashStacks : [ ] } ,
3738 logo : { doStopTurtles : jest . fn ( ) } ,
@@ -75,6 +76,7 @@ describe("PlanetInterface", () => {
7576
7677 beforeEach ( ( ) => {
7778 planetInterface = new PlanetInterface ( mockActivity ) ;
79+ mockActivity . errorMsg . mockClear ( ) ;
7880 } ) ;
7981
8082 test ( "hideMusicBlocks hides relevant elements and disables DOM events" , ( ) => {
@@ -108,6 +110,7 @@ describe("PlanetInterface", () => {
108110 } ) ;
109111
110112 test ( "openPlanet calls saveLocally, hideMusicBlocks, and showPlanet" , ( ) => {
113+ planetInterface . planet = { ProjectStorage : { } , open : jest . fn ( ) } ;
111114 jest . spyOn ( planetInterface , "saveLocally" ) . mockImplementation ( ( ) => { } ) ;
112115 jest . spyOn ( planetInterface , "hideMusicBlocks" ) . mockImplementation ( ( ) => { } ) ;
113116 jest . spyOn ( planetInterface , "showPlanet" ) . mockImplementation ( ( ) => { } ) ;
@@ -117,6 +120,23 @@ describe("PlanetInterface", () => {
117120 expect ( planetInterface . showPlanet ) . toHaveBeenCalled ( ) ;
118121 } ) ;
119122
123+ test ( "openPlanet: does not crash when Planet backend is unavailable" , ( ) => {
124+ const errorSpy = jest . spyOn ( console , "error" ) . mockImplementation ( ( ) => { } ) ;
125+ planetInterface . planet = null ;
126+ jest . spyOn ( planetInterface , "saveLocally" ) ;
127+ jest . spyOn ( planetInterface , "hideMusicBlocks" ) ;
128+ jest . spyOn ( planetInterface , "showPlanet" ) ;
129+
130+ expect ( ( ) => planetInterface . openPlanet ( ) ) . not . toThrow ( ) ;
131+ expect ( planetInterface . saveLocally ) . not . toHaveBeenCalled ( ) ;
132+ expect ( planetInterface . hideMusicBlocks ) . not . toHaveBeenCalled ( ) ;
133+ expect ( planetInterface . showPlanet ) . not . toHaveBeenCalled ( ) ;
134+ expect ( errorSpy ) . toHaveBeenCalledWith (
135+ "[PlanetInterface] openPlanet called before Planet is ready."
136+ ) ;
137+ errorSpy . mockRestore ( ) ;
138+ } ) ;
139+
120140 test ( "closePlanet calls hidePlanet and showMusicBlocks" , ( ) => {
121141 jest . spyOn ( planetInterface , "hidePlanet" ) . mockImplementation ( ( ) => { } ) ;
122142 jest . spyOn ( planetInterface , "showMusicBlocks" ) . mockImplementation ( ( ) => { } ) ;
@@ -189,14 +209,26 @@ describe("PlanetInterface", () => {
189209 doSVG . mockReturnValue ( "" ) ;
190210 const D = { x : 1 } ;
191211 mockActivity . prepareExport . mockReturnValue ( D ) ;
212+ mockActivity . stage . update . mockClear ( ) ;
192213
193214 planetInterface . planet = { ProjectStorage : { saveLocally : jest . fn ( ) } } ;
194215
195216 return planetInterface . saveLocally ( ) . then ( ( ) => {
217+ expect ( mockActivity . stage . update ) . toHaveBeenCalledWith ( ) ;
196218 expect ( planetInterface . planet . ProjectStorage . saveLocally ) . toHaveBeenCalledWith ( D , null ) ;
197219 } ) ;
198220 } ) ;
199221
222+ test ( "saveLocally: returns null without throwing when Planet storage is unavailable" , async ( ) => {
223+ const errorSpy = jest . spyOn ( console , "error" ) . mockImplementation ( ( ) => { } ) ;
224+ planetInterface . planet = null ;
225+
226+ await expect ( planetInterface . saveLocally ( ) ) . resolves . toBeNull ( ) ;
227+ expect ( errorSpy ) . toHaveBeenCalledWith (
228+ "[PlanetInterface] saveLocally called before Planet storage is ready."
229+ ) ;
230+ errorSpy . mockRestore ( ) ;
231+ } ) ;
200232 test ( "getCurrentProjectDescription/Image/TimeLastSaved" , ( ) => {
201233 const D = new Date ( 2020 , 1 , 1 ) ;
202234 planetInterface . planet = {
@@ -369,10 +401,9 @@ describe("PlanetInterface", () => {
369401 it ( "loadProjectFromData shows error and returns early if data is undefined" , ( ) => {
370402 const saved_ = global . _ ;
371403 global . _ = jest . fn ( str => str ) ;
372- planetInterface . errorMsg = jest . fn ( ) ;
373404 planetInterface . iframe = { style : { display : "" } } ;
374405 planetInterface . loadProjectFromData ( undefined , false ) ;
375- expect ( planetInterface . errorMsg ) . toHaveBeenCalledWith ( "project undefined" ) ;
406+ expect ( mockActivity . errorMsg ) . toHaveBeenCalledWith ( "project undefined" ) ;
376407 global . _ = saved_ ;
377408 } ) ;
378409
@@ -399,12 +430,11 @@ describe("PlanetInterface", () => {
399430 delete document . attachEvent ;
400431 } ) ;
401432
402- it ( "loadProjectFromData catches JSON parse errors and calls errorMsg" , ( ) => {
433+ it ( "loadProjectFromData catches JSON parse errors and calls activity. errorMsg" , ( ) => {
403434 planetInterface . iframe = { style : { display : "" } } ;
404435 planetInterface . getCurrentProjectName = jest . fn ( ( ) => "foo" ) ;
405- planetInterface . errorMsg = jest . fn ( ) ;
406436 planetInterface . loadProjectFromData ( "invalid json" ) ;
407- expect ( planetInterface . errorMsg ) . toHaveBeenCalledWith ( expect . any ( SyntaxError ) ) ;
437+ expect ( mockActivity . errorMsg ) . toHaveBeenCalledWith ( expect . any ( SyntaxError ) ) ;
408438 } ) ;
409439
410440 it ( "saveLocally handles quota exceeded error and shows storage warning" , ( ) => {
0 commit comments